1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _func.d) 9 */ 10 11 module ddmd.func; 12 13 import core.stdc.stdio; 14 import core.stdc..string; 15 import ddmd.aggregate; 16 import ddmd.arraytypes; 17 import ddmd.gluelayer; 18 import ddmd.dclass; 19 import ddmd.declaration; 20 import ddmd.delegatize; 21 import ddmd.dinterpret; 22 import ddmd.dmodule; 23 import ddmd.dscope; 24 import ddmd.dstruct; 25 import ddmd.dsymbol; 26 import ddmd.dtemplate; 27 import ddmd.errors; 28 import ddmd.escape; 29 import ddmd.expression; 30 import ddmd.globals; 31 import ddmd.hdrgen; 32 import ddmd.id; 33 import ddmd.identifier; 34 import ddmd.init; 35 import ddmd.mars; 36 import ddmd.mtype; 37 import ddmd.nogc; 38 import ddmd.objc; 39 import ddmd.opover; 40 import ddmd.root.filename; 41 import ddmd.root.outbuffer; 42 import ddmd.root.rootobject; 43 import ddmd.statementsem; 44 import ddmd.statement; 45 import ddmd.target; 46 import ddmd.tokens; 47 import ddmd.visitor; 48 49 enum ILS : int 50 { 51 ILSuninitialized, // not computed yet 52 ILSno, // cannot inline 53 ILSyes, // can inline 54 } 55 56 alias ILSuninitialized = ILS.ILSuninitialized; 57 alias ILSno = ILS.ILSno; 58 alias ILSyes = ILS.ILSyes; 59 60 enum BUILTIN : int 61 { 62 BUILTINunknown = -1, // not known if this is a builtin 63 BUILTINno, // this is not a builtin 64 BUILTINyes, // this is a builtin 65 } 66 67 alias BUILTINunknown = BUILTIN.BUILTINunknown; 68 alias BUILTINno = BUILTIN.BUILTINno; 69 alias BUILTINyes = BUILTIN.BUILTINyes; 70 71 /* A visitor to walk entire statements and provides ability to replace any sub-statements. 72 */ 73 extern (C++) class StatementRewriteWalker : Visitor 74 { 75 alias visit = super.visit; 76 77 /* Point the currently visited statement. 78 * By using replaceCurrent() method, you can replace AST during walking. 79 */ 80 Statement* ps; 81 82 public: 83 final void visitStmt(ref Statement s) 84 { 85 ps = &s; 86 s.accept(this); 87 } 88 89 final void replaceCurrent(Statement s) 90 { 91 *ps = s; 92 } 93 94 override void visit(ErrorStatement s) 95 { 96 } 97 98 override void visit(PeelStatement s) 99 { 100 if (s.s) 101 visitStmt(s.s); 102 } 103 104 override void visit(ExpStatement s) 105 { 106 } 107 108 override void visit(DtorExpStatement s) 109 { 110 } 111 112 override void visit(CompileStatement s) 113 { 114 } 115 116 override void visit(CompoundStatement s) 117 { 118 if (s.statements && s.statements.dim) 119 { 120 for (size_t i = 0; i < s.statements.dim; i++) 121 { 122 if ((*s.statements)[i]) 123 visitStmt((*s.statements)[i]); 124 } 125 } 126 } 127 128 override void visit(CompoundDeclarationStatement s) 129 { 130 visit(cast(CompoundStatement)s); 131 } 132 133 override void visit(UnrolledLoopStatement s) 134 { 135 if (s.statements && s.statements.dim) 136 { 137 for (size_t i = 0; i < s.statements.dim; i++) 138 { 139 if ((*s.statements)[i]) 140 visitStmt((*s.statements)[i]); 141 } 142 } 143 } 144 145 override void visit(ScopeStatement s) 146 { 147 if (s.statement) 148 visitStmt(s.statement); 149 } 150 151 override void visit(WhileStatement s) 152 { 153 if (s._body) 154 visitStmt(s._body); 155 } 156 157 override void visit(DoStatement s) 158 { 159 if (s._body) 160 visitStmt(s._body); 161 } 162 163 override void visit(ForStatement s) 164 { 165 if (s._init) 166 visitStmt(s._init); 167 if (s._body) 168 visitStmt(s._body); 169 } 170 171 override void visit(ForeachStatement s) 172 { 173 if (s._body) 174 visitStmt(s._body); 175 } 176 177 override void visit(ForeachRangeStatement s) 178 { 179 if (s._body) 180 visitStmt(s._body); 181 } 182 183 override void visit(IfStatement s) 184 { 185 if (s.ifbody) 186 visitStmt(s.ifbody); 187 if (s.elsebody) 188 visitStmt(s.elsebody); 189 } 190 191 override void visit(ConditionalStatement s) 192 { 193 } 194 195 override void visit(PragmaStatement s) 196 { 197 } 198 199 override void visit(StaticAssertStatement s) 200 { 201 } 202 203 override void visit(SwitchStatement s) 204 { 205 if (s._body) 206 visitStmt(s._body); 207 } 208 209 override void visit(CaseStatement s) 210 { 211 if (s.statement) 212 visitStmt(s.statement); 213 } 214 215 override void visit(CaseRangeStatement s) 216 { 217 if (s.statement) 218 visitStmt(s.statement); 219 } 220 221 override void visit(DefaultStatement s) 222 { 223 if (s.statement) 224 visitStmt(s.statement); 225 } 226 227 override void visit(GotoDefaultStatement s) 228 { 229 } 230 231 override void visit(GotoCaseStatement s) 232 { 233 } 234 235 override void visit(SwitchErrorStatement s) 236 { 237 } 238 239 override void visit(ReturnStatement s) 240 { 241 } 242 243 override void visit(BreakStatement s) 244 { 245 } 246 247 override void visit(ContinueStatement s) 248 { 249 } 250 251 override void visit(SynchronizedStatement s) 252 { 253 if (s._body) 254 visitStmt(s._body); 255 } 256 257 override void visit(WithStatement s) 258 { 259 if (s._body) 260 visitStmt(s._body); 261 } 262 263 override void visit(TryCatchStatement s) 264 { 265 if (s._body) 266 visitStmt(s._body); 267 if (s.catches && s.catches.dim) 268 { 269 for (size_t i = 0; i < s.catches.dim; i++) 270 { 271 Catch c = (*s.catches)[i]; 272 if (c && c.handler) 273 visitStmt(c.handler); 274 } 275 } 276 } 277 278 override void visit(TryFinallyStatement s) 279 { 280 if (s._body) 281 visitStmt(s._body); 282 if (s.finalbody) 283 visitStmt(s.finalbody); 284 } 285 286 override void visit(OnScopeStatement s) 287 { 288 } 289 290 override void visit(ThrowStatement s) 291 { 292 } 293 294 override void visit(DebugStatement s) 295 { 296 if (s.statement) 297 visitStmt(s.statement); 298 } 299 300 override void visit(GotoStatement s) 301 { 302 } 303 304 override void visit(LabelStatement s) 305 { 306 if (s.statement) 307 visitStmt(s.statement); 308 } 309 310 override void visit(AsmStatement s) 311 { 312 } 313 314 override void visit(ImportStatement s) 315 { 316 } 317 } 318 319 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. 320 */ 321 extern (C++) final class NrvoWalker : StatementRewriteWalker 322 { 323 alias visit = super.visit; 324 public: 325 FuncDeclaration fd; 326 Scope* sc; 327 328 override void visit(ReturnStatement s) 329 { 330 // See if all returns are instead to be replaced with a goto returnLabel; 331 if (fd.returnLabel) 332 { 333 /* Rewrite: 334 * return exp; 335 * as: 336 * vresult = exp; goto Lresult; 337 */ 338 auto gs = new GotoStatement(s.loc, Id.returnLabel); 339 gs.label = fd.returnLabel; 340 341 Statement s1 = gs; 342 if (s.exp) 343 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); 344 345 replaceCurrent(s1); 346 } 347 } 348 349 override void visit(TryFinallyStatement s) 350 { 351 DtorExpStatement des; 352 if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && fd.nrvo_var == des.var) 353 { 354 /* Normally local variable dtors are called regardless exceptions. 355 * But for nrvo_var, its dtor should be called only when exception is thrown. 356 * 357 * Rewrite: 358 * try { s->body; } finally { nrvo_var->edtor; } 359 * // equivalent with: 360 * // s->body; scope(exit) nrvo_var->edtor; 361 * as: 362 * try { s->body; } catch(Throwable __o) { nrvo_var->edtor; throw __o; } 363 * // equivalent with: 364 * // s->body; scope(failure) nrvo_var->edtor; 365 */ 366 Statement sexception = new DtorExpStatement(Loc(), fd.nrvo_var.edtor, fd.nrvo_var); 367 Identifier id = Identifier.generateId("__o"); 368 369 Statement handler = new PeelStatement(sexception); 370 if (sexception.blockExit(fd, false) & BEfallthru) 371 { 372 auto ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id)); 373 ts.internalThrow = true; 374 handler = new CompoundStatement(Loc(), handler, ts); 375 } 376 377 auto catches = new Catches(); 378 auto ctch = new Catch(Loc(), getThrowable(), id, handler); 379 ctch.internalCatch = true; 380 ctch.semantic(sc); // Run semantic to resolve identifier '__o' 381 catches.push(ctch); 382 383 Statement s2 = new TryCatchStatement(Loc(), s._body, catches); 384 replaceCurrent(s2); 385 s2.accept(this); 386 } 387 else 388 StatementRewriteWalker.visit(s); 389 } 390 } 391 392 enum FUNCFLAGpurityInprocess = 1; // working on determining purity 393 enum FUNCFLAGsafetyInprocess = 2; // working on determining safety 394 enum FUNCFLAGnothrowInprocess = 4; // working on determining nothrow 395 enum FUNCFLAGnogcInprocess = 8; // working on determining @nogc 396 enum FUNCFLAGreturnInprocess = 0x10; // working on inferring 'return' for parameters 397 enum FUNCFLAGinlineScanned = 0x20; // function has been scanned for inline possibilities 398 399 400 /*********************************************************** 401 */ 402 extern (C++) class FuncDeclaration : Declaration 403 { 404 Types* fthrows; // Array of Type's of exceptions (not used) 405 Statement frequire; 406 Statement fensure; 407 Statement fbody; 408 409 FuncDeclarations foverrides; // functions this function overrides 410 FuncDeclaration fdrequire; // function that does the in contract 411 FuncDeclaration fdensure; // function that does the out contract 412 413 const(char)* mangleString; // mangled symbol created from mangleExact() 414 415 Identifier outId; // identifier for out statement 416 VarDeclaration vresult; // variable corresponding to outId 417 LabelDsymbol returnLabel; // where the return goes 418 419 // used to prevent symbols in different 420 // scopes from having the same name 421 DsymbolTable localsymtab; 422 VarDeclaration vthis; // 'this' parameter (member and nested) 423 VarDeclaration v_arguments; // '_arguments' parameter 424 Objc_FuncDeclaration objc; 425 426 VarDeclaration v_argptr; // '_argptr' variable 427 VarDeclarations* parameters; // Array of VarDeclaration's for parameters 428 DsymbolTable labtab; // statement label symbol table 429 Dsymbol overnext; // next in overload list 430 FuncDeclaration overnext0; // next in overload list (only used during IFTI) 431 Loc endloc; // location of closing curly bracket 432 int vtblIndex = -1; // for member functions, index into vtbl[] 433 bool naked; // true if naked 434 bool generated; // true if function was generated by the compiler rather than 435 // supplied by the user 436 ILS inlineStatusStmt = ILSuninitialized; 437 ILS inlineStatusExp = ILSuninitialized; 438 PINLINE inlining = PINLINEdefault; 439 440 CompiledCtfeFunction* ctfeCode; // Compiled code for interpreter 441 int inlineNest; // !=0 if nested inline 442 bool isArrayOp; // true if array operation 443 // true if errors in semantic3 this function's frame ptr 444 bool semantic3Errors; 445 ForeachStatement fes; // if foreach body, this is the foreach 446 BaseClass* interfaceVirtual; // if virtual, but only appears in base interface vtbl[] 447 bool introducing; // true if 'introducing' function 448 // if !=NULL, then this is the type 449 // of the 'introducing' function 450 // this one is overriding 451 Type tintro; 452 bool inferRetType; // true if return type is to be inferred 453 StorageClass storage_class2; // storage class for template onemember's 454 455 // Things that should really go into Scope 456 457 // 1 if there's a return exp; statement 458 // 2 if there's a throw statement 459 // 4 if there's an assert(0) 460 // 8 if there's inline asm 461 int hasReturnExp; 462 463 // Support for NRVO (named return value optimization) 464 bool nrvo_can = true; // true means we can do it 465 VarDeclaration nrvo_var; // variable to replace with shidden 466 Symbol* shidden; // hidden pointer passed to function 467 468 ReturnStatements* returns; 469 470 GotoStatements* gotos; // Gotos with forward references 471 472 // set if this is a known, builtin function we can evaluate at compile time 473 BUILTIN builtin = BUILTINunknown; 474 475 // set if someone took the address of this function 476 int tookAddressOf; 477 478 bool requiresClosure; // this function needs a closure 479 480 // local variables in this function which are referenced by nested functions 481 VarDeclarations closureVars; 482 // Sibling nested functions which called this one 483 FuncDeclarations siblingCallers; 484 485 FuncDeclarations *inlinedNestedCallees; 486 487 uint flags; // FUNCFLAGxxxxx 488 489 final extern (D) this(Loc loc, Loc endloc, Identifier id, StorageClass storage_class, Type type) 490 { 491 super(id); 492 objc = Objc_FuncDeclaration(this); 493 //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); 494 //printf("storage_class = x%x\n", storage_class); 495 this.storage_class = storage_class; 496 this.type = type; 497 if (type) 498 { 499 // Normalize storage_class, because function-type related attributes 500 // are already set in the 'type' in parsing phase. 501 this.storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR); 502 } 503 this.loc = loc; 504 this.endloc = endloc; 505 /* The type given for "infer the return type" is a TypeFunction with 506 * NULL for the return type. 507 */ 508 inferRetType = (type && type.nextOf() is null); 509 } 510 511 override Dsymbol syntaxCopy(Dsymbol s) 512 { 513 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); 514 FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); 515 f.outId = outId; 516 f.frequire = frequire ? frequire.syntaxCopy() : null; 517 f.fensure = fensure ? fensure.syntaxCopy() : null; 518 f.fbody = fbody ? fbody.syntaxCopy() : null; 519 assert(!fthrows); // deprecated 520 return f; 521 } 522 523 // Do the semantic analysis on the external interface to the function. 524 override void semantic(Scope* sc) 525 { 526 TypeFunction f; 527 AggregateDeclaration ad; 528 InterfaceDeclaration id; 529 530 version (none) 531 { 532 printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc.linkage); 533 if (isFuncLiteralDeclaration()) 534 printf("\tFuncLiteralDeclaration()\n"); 535 printf("sc->parent = %s, parent = %s\n", sc.parent.toChars(), parent ? parent.toChars() : ""); 536 printf("type: %p, %s\n", type, type.toChars()); 537 } 538 539 if (semanticRun != PASSinit && isFuncLiteralDeclaration()) 540 { 541 /* Member functions that have return types that are 542 * forward references can have semantic() run more than 543 * once on them. 544 * See test\interface2.d, test20 545 */ 546 return; 547 } 548 549 if (semanticRun >= PASSsemanticdone) 550 return; 551 assert(semanticRun <= PASSsemantic); 552 semanticRun = PASSsemantic; 553 554 if (_scope) 555 { 556 sc = _scope; 557 _scope = null; 558 } 559 560 parent = sc.parent; 561 Dsymbol parent = toParent(); 562 563 foverrides.setDim(0); // reset in case semantic() is being retried for this function 564 565 storage_class |= sc.stc & ~STCref; 566 ad = isThis(); 567 if (ad) 568 { 569 storage_class |= ad.storage_class & (STC_TYPECTOR | STCsynchronized); 570 ad.makeNested(); 571 } 572 if (sc.func) 573 storage_class |= sc.func.storage_class & STCdisable; 574 // Remove prefix storage classes silently. 575 if ((storage_class & STC_TYPECTOR) && !(ad || isNested())) 576 storage_class &= ~STC_TYPECTOR; 577 578 //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal()); 579 580 FuncLiteralDeclaration fld = isFuncLiteralDeclaration(); 581 if (fld && fld.treq) 582 { 583 Type treq = fld.treq; 584 assert(treq.nextOf().ty == Tfunction); 585 if (treq.ty == Tdelegate) 586 fld.tok = TOKdelegate; 587 else if (treq.ty == Tpointer && treq.nextOf().ty == Tfunction) 588 fld.tok = TOKfunction; 589 else 590 assert(0); 591 linkage = (cast(TypeFunction)treq.nextOf()).linkage; 592 } 593 else 594 linkage = sc.linkage; 595 inlining = sc.inlining; 596 protection = sc.protection; 597 userAttribDecl = sc.userAttribDecl; 598 599 if (!originalType) 600 originalType = type.syntaxCopy(); 601 if (!type.deco) 602 { 603 sc = sc.push(); 604 sc.stc |= storage_class & (STCdisable | STCdeprecated); // forward to function type 605 606 TypeFunction tf = cast(TypeFunction)type; 607 if (sc.func) 608 { 609 /* If the nesting parent is pure without inference, 610 * then this function defaults to pure too. 611 * 612 * auto foo() pure { 613 * auto bar() {} // become a weak purity funciton 614 * class C { // nested class 615 * auto baz() {} // become a weak purity funciton 616 * } 617 * 618 * static auto boo() {} // typed as impure 619 * // Even though, boo cannot call any impure functions. 620 * // See also Expression::checkPurity(). 621 * } 622 */ 623 if (tf.purity == PUREimpure && (isNested() || isThis())) 624 { 625 FuncDeclaration fd = null; 626 for (Dsymbol p = toParent2(); p; p = p.toParent2()) 627 { 628 if (AggregateDeclaration adx = p.isAggregateDeclaration()) 629 { 630 if (adx.isNested()) 631 continue; 632 break; 633 } 634 if ((fd = p.isFuncDeclaration()) !is null) 635 break; 636 } 637 638 /* If the parent's purity is inferred, then this function's purity needs 639 * to be inferred first. 640 */ 641 if (fd && fd.isPureBypassingInference() >= PUREweak && !isInstantiated()) 642 { 643 tf.purity = PUREfwdref; // default to pure 644 } 645 } 646 } 647 648 if (tf.isref) 649 sc.stc |= STCref; 650 if (tf.isscope) 651 sc.stc |= STCscope; 652 if (tf.isnothrow) 653 sc.stc |= STCnothrow; 654 if (tf.isnogc) 655 sc.stc |= STCnogc; 656 if (tf.isproperty) 657 sc.stc |= STCproperty; 658 if (tf.purity == PUREfwdref) 659 sc.stc |= STCpure; 660 if (tf.trust != TRUSTdefault) 661 sc.stc &= ~(STCsafe | STCsystem | STCtrusted); 662 if (tf.trust == TRUSTsafe) 663 sc.stc |= STCsafe; 664 if (tf.trust == TRUSTsystem) 665 sc.stc |= STCsystem; 666 if (tf.trust == TRUSTtrusted) 667 sc.stc |= STCtrusted; 668 669 if (isCtorDeclaration()) 670 { 671 sc.flags |= SCOPEctor; 672 Type tret = ad.handleType(); 673 assert(tret); 674 tret = tret.addStorageClass(storage_class | sc.stc); 675 tret = tret.addMod(type.mod); 676 tf.next = tret; 677 if (ad.isStructDeclaration()) 678 sc.stc |= STCref; 679 } 680 681 sc.linkage = linkage; 682 683 if (!tf.isNaked() && !(isThis() || isNested())) 684 { 685 OutBuffer buf; 686 MODtoBuffer(&buf, tf.mod); 687 error("without 'this' cannot be %s", buf.peekString()); 688 tf.mod = 0; // remove qualifiers 689 } 690 691 /* Apply const, immutable, wild and shared storage class 692 * to the function type. Do this before type semantic. 693 */ 694 auto stc = storage_class; 695 if (type.isImmutable()) 696 stc |= STCimmutable; 697 if (type.isConst()) 698 stc |= STCconst; 699 if (type.isShared() || storage_class & STCsynchronized) 700 stc |= STCshared; 701 if (type.isWild()) 702 stc |= STCwild; 703 type = type.addSTC(stc); 704 705 type = type.semantic(loc, sc); 706 sc = sc.pop(); 707 } 708 if (type.ty != Tfunction) 709 { 710 if (type.ty != Terror) 711 { 712 error("%s must be a function instead of %s", toChars(), type.toChars()); 713 type = Type.terror; 714 } 715 errors = true; 716 return; 717 } 718 else 719 { 720 // Merge back function attributes into 'originalType'. 721 // It's used for mangling, ddoc, and json output. 722 TypeFunction tfo = cast(TypeFunction)originalType; 723 TypeFunction tfx = cast(TypeFunction)type; 724 tfo.mod = tfx.mod; 725 tfo.isscope = tfx.isscope; 726 tfo.isref = tfx.isref; 727 tfo.isnothrow = tfx.isnothrow; 728 tfo.isnogc = tfx.isnogc; 729 tfo.isproperty = tfx.isproperty; 730 tfo.purity = tfx.purity; 731 tfo.trust = tfx.trust; 732 733 storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR); 734 } 735 736 f = cast(TypeFunction)type; 737 size_t nparams = Parameter.dim(f.parameters); 738 739 if ((storage_class & STCauto) && !f.isref && !inferRetType) 740 error("storage class 'auto' has no effect if return type is not inferred"); 741 742 /* Functions can only be 'scope' if they have a 'this' that is a pointer, not a ref 743 */ 744 if (f.isscope && !isNested() && 745 !(ad && ad.isClassDeclaration())) 746 { 747 error("functions cannot be scope"); 748 } 749 750 if (f.isreturn && !needThis()) 751 { 752 error("static member has no 'this' to which 'return' can apply"); 753 } 754 755 if (isAbstract() && !isVirtual()) 756 { 757 const(char)* sfunc; 758 if (isStatic()) 759 sfunc = "static"; 760 else if (protection.kind == PROTprivate || protection.kind == PROTpackage) 761 sfunc = protectionToChars(protection.kind); 762 else 763 sfunc = "non-virtual"; 764 error("%s functions cannot be abstract", sfunc); 765 } 766 767 if (isOverride() && !isVirtual()) 768 { 769 PROTKIND kind = prot().kind; 770 if ((kind == PROTprivate || kind == PROTpackage) && isMember()) 771 error("%s method is not virtual and cannot override", protectionToChars(kind)); 772 else 773 error("cannot override a non-virtual function"); 774 } 775 776 if (isAbstract() && isFinalFunc()) 777 error("cannot be both final and abstract"); 778 version (none) 779 { 780 if (isAbstract() && fbody) 781 error("abstract functions cannot have bodies"); 782 } 783 784 version (none) 785 { 786 if (isStaticConstructor() || isStaticDestructor()) 787 { 788 if (!isStatic() || type.nextOf().ty != Tvoid) 789 error("static constructors / destructors must be static void"); 790 if (f.arguments && f.arguments.dim) 791 error("static constructors / destructors must have empty parameter list"); 792 // BUG: check for invalid storage classes 793 } 794 } 795 796 id = parent.isInterfaceDeclaration(); 797 if (id) 798 { 799 storage_class |= STCabstract; 800 if (isCtorDeclaration() || isPostBlitDeclaration() || isDtorDeclaration() || isInvariantDeclaration() || isNewDeclaration() || isDelete()) 801 error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id.toChars()); 802 if (fbody && isVirtual()) 803 error("function body only allowed in final functions in interface %s", id.toChars()); 804 } 805 if (UnionDeclaration ud = parent.isUnionDeclaration()) 806 { 807 if (isPostBlitDeclaration() || isDtorDeclaration() || isInvariantDeclaration()) 808 error("destructors, postblits and invariants are not allowed in union %s", ud.toChars()); 809 } 810 811 /* Contracts can only appear without a body when they are virtual interface functions 812 */ 813 if (!fbody && (fensure || frequire) && !(id && isVirtual())) 814 error("in and out contracts require function body"); 815 816 if (StructDeclaration sd = parent.isStructDeclaration()) 817 { 818 if (isCtorDeclaration()) 819 { 820 goto Ldone; 821 } 822 } 823 824 if (ClassDeclaration cd = parent.isClassDeclaration()) 825 { 826 if (isCtorDeclaration()) 827 { 828 goto Ldone; 829 } 830 831 if (storage_class & STCabstract) 832 cd.isabstract = ABSyes; 833 834 // if static function, do not put in vtbl[] 835 if (!isVirtual()) 836 { 837 //printf("\tnot virtual\n"); 838 goto Ldone; 839 } 840 // Suppress further errors if the return type is an error 841 if (type.nextOf() == Type.terror) 842 goto Ldone; 843 844 bool may_override = false; 845 for (size_t i = 0; i < cd.baseclasses.dim; i++) 846 { 847 BaseClass* b = (*cd.baseclasses)[i]; 848 ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); 849 if (!cbd) 850 continue; 851 for (size_t j = 0; j < cbd.vtbl.dim; j++) 852 { 853 FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); 854 if (!f2 || f2.ident != ident) 855 continue; 856 if (cbd.parent && cbd.parent.isTemplateInstance()) 857 { 858 if (!f2.functionSemantic()) 859 goto Ldone; 860 } 861 may_override = true; 862 } 863 } 864 if (may_override && type.nextOf() is null) 865 { 866 /* If same name function exists in base class but 'this' is auto return, 867 * cannot find index of base class's vtbl[] to override. 868 */ 869 error("return type inference is not supported if may override base class function"); 870 } 871 872 /* Find index of existing function in base class's vtbl[] to override 873 * (the index will be the same as in cd's current vtbl[]) 874 */ 875 int vi = cd.baseClass ? findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.dim) : -1; 876 877 bool doesoverride = false; 878 switch (vi) 879 { 880 case -1: 881 Lintro: 882 /* Didn't find one, so 883 * This is an 'introducing' function which gets a new 884 * slot in the vtbl[]. 885 */ 886 887 // Verify this doesn't override previous final function 888 if (cd.baseClass) 889 { 890 Dsymbol s = cd.baseClass.search(loc, ident); 891 if (s) 892 { 893 FuncDeclaration f2 = s.isFuncDeclaration(); 894 if (f2) 895 { 896 f2 = f2.overloadExactMatch(type); 897 if (f2 && f2.isFinalFunc() && f2.prot().kind != PROTprivate) 898 error("cannot override final function %s", f2.toPrettyChars()); 899 } 900 } 901 } 902 903 /* These quirky conditions mimic what VC++ appears to do 904 */ 905 if (global.params.mscoff && cd.cpp && 906 cd.baseClass && cd.baseClass.vtbl.dim) 907 { 908 /* if overriding an interface function, then this is not 909 * introducing and don't put it in the class vtbl[] 910 */ 911 interfaceVirtual = overrideInterface(); 912 if (interfaceVirtual) 913 { 914 //printf("\tinterface function %s\n", toChars()); 915 cd.vtblFinal.push(this); 916 goto Linterfaces; 917 } 918 } 919 920 if (isFinalFunc()) 921 { 922 // Don't check here, as it may override an interface function 923 //if (isOverride()) 924 // error("is marked as override, but does not override any function"); 925 cd.vtblFinal.push(this); 926 } 927 else 928 { 929 //printf("\tintroducing function %s\n", toChars()); 930 introducing = 1; 931 if (cd.cpp && Target.reverseCppOverloads) 932 { 933 // with dmc, overloaded functions are grouped and in reverse order 934 vtblIndex = cast(int)cd.vtbl.dim; 935 for (size_t i = 0; i < cd.vtbl.dim; i++) 936 { 937 if (cd.vtbl[i].ident == ident && cd.vtbl[i].parent == parent) 938 { 939 vtblIndex = cast(int)i; 940 break; 941 } 942 } 943 // shift all existing functions back 944 for (size_t i = cd.vtbl.dim; i > vtblIndex; i--) 945 { 946 FuncDeclaration fd = cd.vtbl[i - 1].isFuncDeclaration(); 947 assert(fd); 948 fd.vtblIndex++; 949 } 950 cd.vtbl.insert(vtblIndex, this); 951 } 952 else 953 { 954 // Append to end of vtbl[] 955 vi = cast(int)cd.vtbl.dim; 956 cd.vtbl.push(this); 957 vtblIndex = vi; 958 } 959 } 960 break; 961 962 case -2: 963 // can't determine because of forward references 964 return; 965 966 default: 967 { 968 FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); 969 FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); 970 // This function is covariant with fdv 971 972 if (fdc == this) 973 { 974 doesoverride = true; 975 break; 976 } 977 978 if (fdc.toParent() == parent) 979 { 980 //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", 981 // vi, this, this->toChars(), this->type->toChars(), this->loc.toChars(), 982 // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(), 983 // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars()); 984 985 // fdc overrides fdv exactly, then this introduces new function. 986 if (fdc.type.mod == fdv.type.mod && this.type.mod != fdv.type.mod) 987 goto Lintro; 988 } 989 990 // This function overrides fdv 991 if (fdv.isFinalFunc()) 992 error("cannot override final function %s", fdv.toPrettyChars()); 993 994 doesoverride = true; 995 if (!isOverride()) 996 .error(loc, "cannot implicitly override base class method %s with %s; add 'override' attribute", fdv.toPrettyChars(), toPrettyChars()); 997 if (fdc.toParent() == parent) 998 { 999 // If both are mixins, or both are not, then error. 1000 // If either is not, the one that is not overrides the other. 1001 bool thismixin = this.parent.isClassDeclaration() !is null; 1002 bool fdcmixin = fdc.parent.isClassDeclaration() !is null; 1003 if (thismixin == fdcmixin) 1004 { 1005 error("multiple overrides of same function"); 1006 } 1007 else if (!thismixin) // fdc overrides fdv 1008 { 1009 // this doesn't override any function 1010 break; 1011 } 1012 } 1013 cd.vtbl[vi] = this; 1014 vtblIndex = vi; 1015 1016 /* Remember which functions this overrides 1017 */ 1018 foverrides.push(fdv); 1019 1020 /* This works by whenever this function is called, 1021 * it actually returns tintro, which gets dynamically 1022 * cast to type. But we know that tintro is a base 1023 * of type, so we could optimize it by not doing a 1024 * dynamic cast, but just subtracting the isBaseOf() 1025 * offset if the value is != null. 1026 */ 1027 1028 if (fdv.tintro) 1029 tintro = fdv.tintro; 1030 else if (!type.equals(fdv.type)) 1031 { 1032 /* Only need to have a tintro if the vptr 1033 * offsets differ 1034 */ 1035 int offset; 1036 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) 1037 { 1038 tintro = fdv.type; 1039 } 1040 } 1041 break; 1042 } 1043 } 1044 1045 /* Go through all the interface bases. 1046 * If this function is covariant with any members of those interface 1047 * functions, set the tintro. 1048 */ 1049 Linterfaces: 1050 foreach (b; cd.interfaces) 1051 { 1052 vi = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); 1053 switch (vi) 1054 { 1055 case -1: 1056 break; 1057 1058 case -2: 1059 // can't determine because of forward references 1060 return; 1061 1062 default: 1063 { 1064 auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; 1065 Type ti = null; 1066 1067 /* Remember which functions this overrides 1068 */ 1069 foverrides.push(fdv); 1070 1071 /* Should we really require 'override' when implementing 1072 * an interface function? 1073 */ 1074 //if (!isOverride()) 1075 // warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); 1076 1077 if (fdv.tintro) 1078 ti = fdv.tintro; 1079 else if (!type.equals(fdv.type)) 1080 { 1081 /* Only need to have a tintro if the vptr 1082 * offsets differ 1083 */ 1084 int offset; 1085 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) 1086 { 1087 ti = fdv.type; 1088 } 1089 } 1090 if (ti) 1091 { 1092 if (tintro) 1093 { 1094 if (!tintro.nextOf().equals(ti.nextOf()) && !tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(tintro.nextOf(), null)) 1095 { 1096 error("incompatible covariant types %s and %s", tintro.toChars(), ti.toChars()); 1097 } 1098 } 1099 tintro = ti; 1100 } 1101 goto L2; 1102 } 1103 } 1104 } 1105 1106 if (!doesoverride && isOverride() && (type.nextOf() || !may_override)) 1107 { 1108 BaseClass* bc = null; 1109 Dsymbol s = null; 1110 for (size_t i = 0; i < cd.baseclasses.dim; i++) 1111 { 1112 bc = (*cd.baseclasses)[i]; 1113 s = bc.sym.search_correct(ident); 1114 if (s) 1115 break; 1116 } 1117 1118 if (s) 1119 error("does not override any function, did you mean to override '%s%s'?", 1120 bc.sym.isCPPclass() ? "extern (C++) ".ptr : "".ptr, s.toPrettyChars()); 1121 else 1122 error("does not override any function"); 1123 } 1124 1125 L2: 1126 /* Go through all the interface bases. 1127 * Disallow overriding any final functions in the interface(s). 1128 */ 1129 foreach (b; cd.interfaces) 1130 { 1131 if (b.sym) 1132 { 1133 Dsymbol s = search_function(b.sym, ident); 1134 if (s) 1135 { 1136 FuncDeclaration f2 = s.isFuncDeclaration(); 1137 if (f2) 1138 { 1139 f2 = f2.overloadExactMatch(type); 1140 if (f2 && f2.isFinalFunc() && f2.prot().kind != PROTprivate) 1141 error("cannot override final function %s.%s", b.sym.toChars(), f2.toPrettyChars()); 1142 } 1143 } 1144 } 1145 } 1146 } 1147 else if (isOverride() && !parent.isTemplateInstance()) 1148 error("override only applies to class member functions"); 1149 1150 // Reflect this->type to f because it could be changed by findVtblIndex 1151 assert(type.ty == Tfunction); 1152 f = cast(TypeFunction)type; 1153 1154 /* Do not allow template instances to add virtual functions 1155 * to a class. 1156 */ 1157 if (isVirtual()) 1158 { 1159 TemplateInstance ti = parent.isTemplateInstance(); 1160 if (ti) 1161 { 1162 // Take care of nested templates 1163 while (1) 1164 { 1165 TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); 1166 if (!ti2) 1167 break; 1168 ti = ti2; 1169 } 1170 1171 // If it's a member template 1172 ClassDeclaration cd = ti.tempdecl.isClassMember(); 1173 if (cd) 1174 { 1175 error("cannot use template to add virtual function to class '%s'", cd.toChars()); 1176 } 1177 } 1178 } 1179 1180 if (isMain()) 1181 { 1182 // Check parameters to see if they are either () or (char[][] args) 1183 switch (nparams) 1184 { 1185 case 0: 1186 break; 1187 1188 case 1: 1189 { 1190 Parameter fparam0 = Parameter.getNth(f.parameters, 0); 1191 if (fparam0.type.ty != Tarray || fparam0.type.nextOf().ty != Tarray || fparam0.type.nextOf().nextOf().ty != Tchar || fparam0.storageClass & (STCout | STCref | STClazy)) 1192 goto Lmainerr; 1193 break; 1194 } 1195 default: 1196 goto Lmainerr; 1197 } 1198 1199 if (!f.nextOf()) 1200 error("must return int or void"); 1201 else if (f.nextOf().ty != Tint32 && f.nextOf().ty != Tvoid) 1202 error("must return int or void, not %s", f.nextOf().toChars()); 1203 if (f.varargs) 1204 { 1205 Lmainerr: 1206 error("parameters must be main() or main(string[] args)"); 1207 } 1208 } 1209 1210 if (isVirtual() && semanticRun != PASSsemanticdone) 1211 { 1212 /* Rewrite contracts as nested functions, then call them. 1213 * Doing it as nested functions means that overriding functions 1214 * can call them. 1215 */ 1216 if (frequire) 1217 { 1218 /* in { ... } 1219 * becomes: 1220 * void __require() { ... } 1221 * __require(); 1222 */ 1223 Loc loc = frequire.loc; 1224 auto tf = new TypeFunction(null, Type.tvoid, 0, LINKd); 1225 tf.isnothrow = f.isnothrow; 1226 tf.isnogc = f.isnogc; 1227 tf.purity = f.purity; 1228 tf.trust = f.trust; 1229 auto fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf); 1230 fd.fbody = frequire; 1231 Statement s1 = new ExpStatement(loc, fd); 1232 Expression e = new CallExp(loc, new VarExp(loc, fd, false), cast(Expressions*)null); 1233 Statement s2 = new ExpStatement(loc, e); 1234 frequire = new CompoundStatement(loc, s1, s2); 1235 fdrequire = fd; 1236 } 1237 1238 if (!outId && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid) 1239 outId = Id.result; // provide a default 1240 1241 if (fensure) 1242 { 1243 /* out (result) { ... } 1244 * becomes: 1245 * void __ensure(ref tret result) { ... } 1246 * __ensure(result); 1247 */ 1248 Loc loc = fensure.loc; 1249 auto fparams = new Parameters(); 1250 Parameter p = null; 1251 if (outId) 1252 { 1253 p = new Parameter(STCref | STCconst, f.nextOf(), outId, null); 1254 fparams.push(p); 1255 } 1256 auto tf = new TypeFunction(fparams, Type.tvoid, 0, LINKd); 1257 tf.isnothrow = f.isnothrow; 1258 tf.isnogc = f.isnogc; 1259 tf.purity = f.purity; 1260 tf.trust = f.trust; 1261 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf); 1262 fd.fbody = fensure; 1263 Statement s1 = new ExpStatement(loc, fd); 1264 Expression eresult = null; 1265 if (outId) 1266 eresult = new IdentifierExp(loc, outId); 1267 Expression e = new CallExp(loc, new VarExp(loc, fd, false), eresult); 1268 Statement s2 = new ExpStatement(loc, e); 1269 fensure = new CompoundStatement(loc, s1, s2); 1270 fdensure = fd; 1271 } 1272 } 1273 1274 Ldone: 1275 /* Purity and safety can be inferred for some functions by examining 1276 * the function body. 1277 */ 1278 if (canInferAttributes(sc)) 1279 initInferAttributes(); 1280 1281 Module.dprogress++; 1282 semanticRun = PASSsemanticdone; 1283 1284 /* Save scope for possible later use (if we need the 1285 * function internals) 1286 */ 1287 _scope = sc.copy(); 1288 _scope.setNoFree(); 1289 1290 static __gshared bool printedMain = false; // semantic might run more than once 1291 if (global.params.verbose && !printedMain) 1292 { 1293 const(char)* type = isMain() ? "main" : isWinMain() ? "winmain" : isDllMain() ? "dllmain" : cast(const(char)*)null; 1294 Module mod = sc._module; 1295 1296 if (type && mod) 1297 { 1298 printedMain = true; 1299 const(char)* name = FileName.searchPath(global.path, mod.srcfile.toChars(), true); 1300 fprintf(global.stdmsg, "entry %-10s\t%s\n", type, name); 1301 } 1302 } 1303 1304 if (fbody && isMain() && sc._module.isRoot()) 1305 genCmain(sc); 1306 1307 assert(type.ty != Terror || errors); 1308 } 1309 1310 override final void semantic2(Scope* sc) 1311 { 1312 if (semanticRun >= PASSsemantic2done) 1313 return; 1314 assert(semanticRun <= PASSsemantic2); 1315 1316 semanticRun = PASSsemantic2; 1317 1318 objc_FuncDeclaration_semantic_setSelector(this, sc); 1319 objc_FuncDeclaration_semantic_validateSelector(this); 1320 if (ClassDeclaration cd = parent.isClassDeclaration()) 1321 { 1322 objc_FuncDeclaration_semantic_checkLinkage(this); 1323 } 1324 } 1325 1326 // Do the semantic analysis on the internals of the function. 1327 override final void semantic3(Scope* sc) 1328 { 1329 VarDeclaration _arguments = null; 1330 1331 if (!parent) 1332 { 1333 if (global.errors) 1334 return; 1335 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); 1336 assert(0); 1337 } 1338 if (errors || isError(parent)) 1339 { 1340 errors = true; 1341 return; 1342 } 1343 //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", parent->toChars(), toChars(), this, sc, loc.toChars()); 1344 //fflush(stdout); 1345 //printf("storage class = x%x %x\n", sc->stc, storage_class); 1346 //{ static int x; if (++x == 2) *(char*)0=0; } 1347 //printf("\tlinkage = %d\n", sc->linkage); 1348 1349 if (ident == Id.assign && !inuse) 1350 { 1351 if (storage_class & STCinference) 1352 { 1353 /* Bugzilla 15044: For generated opAssign function, any errors 1354 * from its body need to be gagged. 1355 */ 1356 uint oldErrors = global.startGagging(); 1357 ++inuse; 1358 semantic3(sc); 1359 --inuse; 1360 if (global.endGagging(oldErrors)) // if errors happened 1361 { 1362 // Disable generated opAssign, because some members forbid identity assignment. 1363 storage_class |= STCdisable; 1364 fbody = null; // remove fbody which contains the error 1365 semantic3Errors = false; 1366 } 1367 return; 1368 } 1369 } 1370 1371 //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract)); 1372 if (semanticRun >= PASSsemantic3) 1373 return; 1374 semanticRun = PASSsemantic3; 1375 semantic3Errors = false; 1376 1377 if (!type || type.ty != Tfunction) 1378 return; 1379 TypeFunction f = cast(TypeFunction)type; 1380 if (!inferRetType && f.next.ty == Terror) 1381 return; 1382 1383 if (!fbody && inferRetType && !f.next) 1384 { 1385 error("has no function body with return type inference"); 1386 return; 1387 } 1388 1389 uint oldErrors = global.errors; 1390 1391 if (frequire) 1392 { 1393 for (size_t i = 0; i < foverrides.dim; i++) 1394 { 1395 FuncDeclaration fdv = foverrides[i]; 1396 if (fdv.fbody && !fdv.frequire) 1397 { 1398 error("cannot have an in contract when overriden function %s does not have an in contract", fdv.toPrettyChars()); 1399 break; 1400 } 1401 } 1402 } 1403 1404 uint fensure_endlin = endloc.linnum; 1405 if (fensure) 1406 if (auto s = fensure.isScopeStatement()) 1407 fensure_endlin = s.endloc.linnum; 1408 1409 frequire = mergeFrequire(frequire); 1410 fensure = mergeFensure(fensure, outId); 1411 if (fbody || frequire || fensure) 1412 { 1413 /* Symbol table into which we place parameters and nested functions, 1414 * solely to diagnose name collisions. 1415 */ 1416 localsymtab = new DsymbolTable(); 1417 1418 // Establish function scope 1419 auto ss = new ScopeDsymbol(); 1420 ss.parent = sc.scopesym; 1421 ss.loc = loc; 1422 ss.endlinnum = endloc.linnum; 1423 Scope* sc2 = sc.push(ss); 1424 sc2.func = this; 1425 sc2.parent = this; 1426 sc2.callSuper = 0; 1427 sc2.sbreak = null; 1428 sc2.scontinue = null; 1429 sc2.sw = null; 1430 sc2.fes = fes; 1431 sc2.linkage = LINKd; 1432 sc2.stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCoverride | STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn | STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem); 1433 sc2.protection = Prot(PROTpublic); 1434 sc2.explicitProtection = 0; 1435 sc2.aligndecl = null; 1436 if (this.ident != Id.require && this.ident != Id.ensure) 1437 sc2.flags = sc.flags & ~SCOPEcontract; 1438 sc2.flags &= ~SCOPEcompile; 1439 sc2.tf = null; 1440 sc2.os = null; 1441 sc2.noctor = 0; 1442 sc2.userAttribDecl = null; 1443 if (sc2.intypeof == 1) 1444 sc2.intypeof = 2; 1445 sc2.fieldinit = null; 1446 sc2.fieldinit_dim = 0; 1447 1448 /* Note: When a lambda is defined immediately under aggregate member 1449 * scope, it should be contextless due to prevent interior pointers. 1450 * e.g. 1451 * // dg points 'this' - it's interior pointer 1452 * class C { int x; void delegate() dg = (){ this.x = 1; }; } 1453 * 1454 * However, lambdas could be used inside typeof, in order to check 1455 * some expressions varidity at compile time. For such case the lambda 1456 * body can access aggregate instance members. 1457 * e.g. 1458 * class C { int x; static assert(is(typeof({ this.x = 1; }))); } 1459 * 1460 * To properly accept it, mark these lambdas as member functions - 1461 * isThis() returns true and isNested() returns false. 1462 */ 1463 if (auto fld = isFuncLiteralDeclaration()) 1464 { 1465 if (auto ad = isMember2()) 1466 { 1467 if (!sc.intypeof) 1468 { 1469 if (fld.tok == TOKdelegate) 1470 error("cannot be %s members", ad.kind()); 1471 else 1472 fld.tok = TOKfunction; 1473 } 1474 else 1475 { 1476 if (fld.tok != TOKfunction) 1477 fld.tok = TOKdelegate; 1478 } 1479 assert(!isNested()); 1480 } 1481 } 1482 1483 // Declare 'this' 1484 auto ad = isThis(); 1485 vthis = declareThis(sc2, ad); 1486 //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis); 1487 //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars()); 1488 1489 // Declare hidden variable _arguments[] and _argptr 1490 if (f.varargs == 1) 1491 { 1492 if (f.linkage == LINKd) 1493 { 1494 // Declare _arguments[] 1495 v_arguments = new VarDeclaration(Loc(), Type.typeinfotypelist.type, Id._arguments_typeinfo, null); 1496 v_arguments.storage_class |= STCtemp | STCparameter; 1497 v_arguments.semantic(sc2); 1498 sc2.insert(v_arguments); 1499 v_arguments.parent = this; 1500 1501 //Type *t = Type::typeinfo->type->constOf()->arrayOf(); 1502 Type t = Type.dtypeinfo.type.arrayOf(); 1503 _arguments = new VarDeclaration(Loc(), t, Id._arguments, null); 1504 _arguments.storage_class |= STCtemp; 1505 _arguments.semantic(sc2); 1506 sc2.insert(_arguments); 1507 _arguments.parent = this; 1508 } 1509 if (f.linkage == LINKd || (f.parameters && Parameter.dim(f.parameters))) 1510 { 1511 // Declare _argptr 1512 Type t = Type.tvalist; 1513 // Init is handled in FuncDeclaration_toObjFile 1514 v_argptr = new VarDeclaration(Loc(), t, Id._argptr, new VoidInitializer(loc)); 1515 v_argptr.storage_class |= STCtemp; 1516 v_argptr.semantic(sc2); 1517 sc2.insert(v_argptr); 1518 v_argptr.parent = this; 1519 } 1520 } 1521 1522 /* Declare all the function parameters as variables 1523 * and install them in parameters[] 1524 */ 1525 size_t nparams = Parameter.dim(f.parameters); 1526 if (nparams) 1527 { 1528 /* parameters[] has all the tuples removed, as the back end 1529 * doesn't know about tuples 1530 */ 1531 parameters = new VarDeclarations(); 1532 parameters.reserve(nparams); 1533 for (size_t i = 0; i < nparams; i++) 1534 { 1535 Parameter fparam = Parameter.getNth(f.parameters, i); 1536 Identifier id = fparam.ident; 1537 StorageClass stc = 0; 1538 if (!id) 1539 { 1540 /* Generate identifier for un-named parameter, 1541 * because we need it later on. 1542 */ 1543 fparam.ident = id = Identifier.generateId("_param_", i); 1544 stc |= STCtemp; 1545 } 1546 Type vtype = fparam.type; 1547 auto v = new VarDeclaration(loc, vtype, id, null); 1548 //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); 1549 stc |= STCparameter; 1550 if (f.varargs == 2 && i + 1 == nparams) 1551 stc |= STCvariadic; 1552 stc |= fparam.storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); 1553 v.storage_class = stc; 1554 v.semantic(sc2); 1555 if (!sc2.insert(v)) 1556 error("parameter %s.%s is already defined", toChars(), v.toChars()); 1557 else 1558 parameters.push(v); 1559 localsymtab.insert(v); 1560 v.parent = this; 1561 } 1562 } 1563 1564 // Declare the tuple symbols and put them in the symbol table, 1565 // but not in parameters[]. 1566 if (f.parameters) 1567 { 1568 for (size_t i = 0; i < f.parameters.dim; i++) 1569 { 1570 Parameter fparam = (*f.parameters)[i]; 1571 if (!fparam.ident) 1572 continue; // never used, so ignore 1573 if (fparam.type.ty == Ttuple) 1574 { 1575 TypeTuple t = cast(TypeTuple)fparam.type; 1576 size_t dim = Parameter.dim(t.arguments); 1577 auto exps = new Objects(); 1578 exps.setDim(dim); 1579 for (size_t j = 0; j < dim; j++) 1580 { 1581 Parameter narg = Parameter.getNth(t.arguments, j); 1582 assert(narg.ident); 1583 VarDeclaration v = sc2.search(Loc(), narg.ident, null).isVarDeclaration(); 1584 assert(v); 1585 Expression e = new VarExp(v.loc, v); 1586 (*exps)[j] = e; 1587 } 1588 assert(fparam.ident); 1589 auto v = new TupleDeclaration(loc, fparam.ident, exps); 1590 //printf("declaring tuple %s\n", v->toChars()); 1591 v.isexp = true; 1592 if (!sc2.insert(v)) 1593 error("parameter %s.%s is already defined", toChars(), v.toChars()); 1594 localsymtab.insert(v); 1595 v.parent = this; 1596 } 1597 } 1598 } 1599 1600 // Precondition invariant 1601 Statement fpreinv = null; 1602 if (addPreInvariant()) 1603 { 1604 Expression e = addInvariant(loc, sc, ad, vthis, isDtorDeclaration() !is null); 1605 if (e) 1606 fpreinv = new ExpStatement(Loc(), e); 1607 } 1608 1609 // Postcondition invariant 1610 Statement fpostinv = null; 1611 if (addPostInvariant()) 1612 { 1613 Expression e = addInvariant(loc, sc, ad, vthis, isCtorDeclaration() !is null); 1614 if (e) 1615 fpostinv = new ExpStatement(Loc(), e); 1616 } 1617 1618 Scope* scout = null; 1619 if (fensure || addPostInvariant()) 1620 { 1621 if ((fensure && global.params.useOut) || fpostinv) 1622 { 1623 returnLabel = new LabelDsymbol(Id.returnLabel); 1624 } 1625 1626 // scope of out contract (need for vresult->semantic) 1627 auto sym = new ScopeDsymbol(); 1628 sym.parent = sc2.scopesym; 1629 sym.loc = loc; 1630 sym.endlinnum = fensure_endlin; 1631 scout = sc2.push(sym); 1632 } 1633 1634 if (fbody) 1635 { 1636 auto sym = new ScopeDsymbol(); 1637 sym.parent = sc2.scopesym; 1638 sym.loc = loc; 1639 sym.endlinnum = endloc.linnum; 1640 sc2 = sc2.push(sym); 1641 1642 auto ad2 = isMember2(); 1643 1644 /* If this is a class constructor 1645 */ 1646 if (ad2 && isCtorDeclaration()) 1647 { 1648 sc2.allocFieldinit(ad2.fields.dim); 1649 foreach (v; ad2.fields) 1650 { 1651 v.ctorinit = 0; 1652 } 1653 } 1654 1655 if (!inferRetType && retStyle(f) != RETstack) 1656 nrvo_can = 0; 1657 1658 bool inferRef = (f.isref && (storage_class & STCauto)); 1659 1660 fbody = fbody.semantic(sc2); 1661 if (!fbody) 1662 fbody = new CompoundStatement(Loc(), new Statements()); 1663 1664 if (naked) 1665 { 1666 fpreinv = null; // can't accommodate with no stack frame 1667 fpostinv = null; 1668 } 1669 1670 assert(type == f || (type.ty == Tfunction && f.purity == PUREimpure && (cast(TypeFunction)type).purity >= PUREfwdref)); 1671 f = cast(TypeFunction)type; 1672 1673 if (inferRetType) 1674 { 1675 // If no return type inferred yet, then infer a void 1676 if (!f.next) 1677 f.next = Type.tvoid; 1678 if (f.checkRetType(loc)) 1679 fbody = new ErrorStatement(); 1680 } 1681 if (global.params.vcomplex && f.next !is null) 1682 f.next.checkComplexTransition(loc); 1683 1684 if (returns && !fbody.isErrorStatement()) 1685 { 1686 for (size_t i = 0; i < returns.dim;) 1687 { 1688 Expression exp = (*returns)[i].exp; 1689 if (exp.op == TOKvar && (cast(VarExp)exp).var == vresult) 1690 { 1691 if (f.next.ty == Tvoid && isMain()) 1692 exp.type = Type.tint32; 1693 else 1694 exp.type = f.next; 1695 // Remove `return vresult;` from returns 1696 returns.remove(i); 1697 continue; 1698 } 1699 if (inferRef && f.isref && !exp.type.constConv(f.next)) // Bugzilla 13336 1700 f.isref = false; 1701 i++; 1702 } 1703 } 1704 if (f.isref) // Function returns a reference 1705 { 1706 if (storage_class & STCauto) 1707 storage_class &= ~STCauto; 1708 } 1709 if (retStyle(f) != RETstack) 1710 nrvo_can = 0; 1711 1712 if (fbody.isErrorStatement()) 1713 { 1714 } 1715 else if (isStaticCtorDeclaration()) 1716 { 1717 /* It's a static constructor. Ensure that all 1718 * ctor consts were initialized. 1719 */ 1720 ScopeDsymbol pd = toParent().isScopeDsymbol(); 1721 for (size_t i = 0; i < pd.members.dim; i++) 1722 { 1723 Dsymbol s = (*pd.members)[i]; 1724 s.checkCtorConstInit(); 1725 } 1726 } 1727 else if (ad2 && isCtorDeclaration()) 1728 { 1729 ClassDeclaration cd = ad2.isClassDeclaration(); 1730 1731 // Verify that all the ctorinit fields got initialized 1732 if (!(sc2.callSuper & CSXthis_ctor)) 1733 { 1734 foreach (i, v; ad2.fields) 1735 { 1736 if (v.isThisDeclaration()) 1737 continue; 1738 if (v.ctorinit == 0) 1739 { 1740 /* Current bugs in the flow analysis: 1741 * 1. union members should not produce error messages even if 1742 * not assigned to 1743 * 2. structs should recognize delegating opAssign calls as well 1744 * as delegating calls to other constructors 1745 */ 1746 if (v.isCtorinit() && !v.type.isMutable() && cd) 1747 error("missing initializer for %s field %s", MODtoChars(v.type.mod), v.toChars()); 1748 else if (v.storage_class & STCnodefaultctor) 1749 .error(loc, "field %s must be initialized in constructor", v.toChars()); 1750 else if (v.type.needsNested()) 1751 .error(loc, "field %s must be initialized in constructor, because it is nested struct", v.toChars()); 1752 } 1753 else 1754 { 1755 bool mustInit = (v.storage_class & STCnodefaultctor || v.type.needsNested()); 1756 if (mustInit && !(sc2.fieldinit[i] & CSXthis_ctor)) 1757 { 1758 error("field %s must be initialized but skipped", v.toChars()); 1759 } 1760 } 1761 } 1762 } 1763 sc2.freeFieldinit(); 1764 1765 if (cd && !(sc2.callSuper & CSXany_ctor) && cd.baseClass && cd.baseClass.ctor) 1766 { 1767 sc2.callSuper = 0; 1768 1769 // Insert implicit super() at start of fbody 1770 FuncDeclaration fd = resolveFuncCall(Loc(), sc2, cd.baseClass.ctor, null, null, null, 1); 1771 if (!fd) 1772 { 1773 error("no match for implicit super() call in constructor"); 1774 } 1775 else if (fd.storage_class & STCdisable) 1776 { 1777 error("cannot call super() implicitly because it is annotated with @disable"); 1778 } 1779 else 1780 { 1781 Expression e1 = new SuperExp(Loc()); 1782 Expression e = new CallExp(Loc(), e1); 1783 e = e.semantic(sc2); 1784 Statement s = new ExpStatement(Loc(), e); 1785 fbody = new CompoundStatement(Loc(), s, fbody); 1786 } 1787 } 1788 //printf("callSuper = x%x\n", sc2->callSuper); 1789 } 1790 1791 int blockexit = BEnone; 1792 if (!fbody.isErrorStatement()) 1793 { 1794 // Check for errors related to 'nothrow'. 1795 uint nothrowErrors = global.errors; 1796 blockexit = fbody.blockExit(this, f.isnothrow); 1797 if (f.isnothrow && (global.errors != nothrowErrors)) 1798 .error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars()); 1799 if (flags & FUNCFLAGnothrowInprocess) 1800 { 1801 if (type == f) 1802 f = cast(TypeFunction)f.copy(); 1803 f.isnothrow = !(blockexit & BEthrow); 1804 } 1805 } 1806 1807 if (fbody.isErrorStatement()) 1808 { 1809 } 1810 else if (ad2 && isCtorDeclaration()) 1811 { 1812 /* Append: 1813 * return this; 1814 * to function body 1815 */ 1816 if (blockexit & BEfallthru) 1817 { 1818 Statement s = new ReturnStatement(loc, null); 1819 s = s.semantic(sc2); 1820 fbody = new CompoundStatement(loc, fbody, s); 1821 hasReturnExp |= 1; 1822 } 1823 } 1824 else if (fes) 1825 { 1826 // For foreach(){} body, append a return 0; 1827 if (blockexit & BEfallthru) 1828 { 1829 Expression e = new IntegerExp(0); 1830 Statement s = new ReturnStatement(Loc(), e); 1831 fbody = new CompoundStatement(Loc(), fbody, s); 1832 hasReturnExp |= 1; 1833 } 1834 assert(!returnLabel); 1835 } 1836 else 1837 { 1838 const(bool) inlineAsm = (hasReturnExp & 8) != 0; 1839 if ((blockexit & BEfallthru) && f.next.ty != Tvoid && !inlineAsm) 1840 { 1841 Expression e; 1842 if (!hasReturnExp) 1843 error("has no return statement, but is expected to return a value of type %s", f.next.toChars()); 1844 else 1845 error("no return exp; or assert(0); at end of function"); 1846 if (global.params.useAssert && !global.params.useInline) 1847 { 1848 /* Add an assert(0, msg); where the missing return 1849 * should be. 1850 */ 1851 e = new AssertExp(endloc, new IntegerExp(0), new StringExp(loc, cast(char*)"missing return expression")); 1852 } 1853 else 1854 e = new HaltExp(endloc); 1855 e = new CommaExp(Loc(), e, f.next.defaultInit()); 1856 e = e.semantic(sc2); 1857 Statement s = new ExpStatement(Loc(), e); 1858 fbody = new CompoundStatement(Loc(), fbody, s); 1859 } 1860 } 1861 1862 if (returns) 1863 { 1864 bool implicit0 = (f.next.ty == Tvoid && isMain()); 1865 Type tret = implicit0 ? Type.tint32 : f.next; 1866 assert(tret.ty != Tvoid); 1867 if (vresult || returnLabel) 1868 buildResultVar(scout ? scout : sc2, tret); 1869 1870 /* Cannot move this loop into NrvoWalker, because 1871 * returns[i] may be in the nested delegate for foreach-body. 1872 */ 1873 for (size_t i = 0; i < returns.dim; i++) 1874 { 1875 ReturnStatement rs = (*returns)[i]; 1876 Expression exp = rs.exp; 1877 if (exp.op == TOKerror) 1878 continue; 1879 if (tret.ty == Terror) 1880 { 1881 // Bugzilla 13702 1882 exp = checkGC(sc2, exp); 1883 continue; 1884 } 1885 1886 if (!exp.implicitConvTo(tret) && parametersIntersect(exp.type)) 1887 { 1888 if (exp.type.immutableOf().implicitConvTo(tret)) 1889 exp = exp.castTo(sc2, exp.type.immutableOf()); 1890 else if (exp.type.wildOf().implicitConvTo(tret)) 1891 exp = exp.castTo(sc2, exp.type.wildOf()); 1892 } 1893 exp = exp.implicitCastTo(sc2, tret); 1894 1895 if (f.isref) 1896 { 1897 // Function returns a reference 1898 exp = exp.toLvalue(sc2, exp); 1899 checkEscapeRef(sc2, exp, false); 1900 } 1901 else 1902 { 1903 exp = exp.optimize(WANTvalue); 1904 1905 /* Bugzilla 10789: 1906 * If NRVO is not possible, all returned lvalues should call their postblits. 1907 */ 1908 if (!nrvo_can) 1909 exp = doCopyOrMove(sc2, exp); 1910 1911 checkEscape(sc2, exp, false); 1912 } 1913 1914 exp = checkGC(sc2, exp); 1915 1916 if (vresult) 1917 { 1918 // Create: return vresult = exp; 1919 exp = new BlitExp(rs.loc, vresult, exp); 1920 exp.type = vresult.type; 1921 1922 if (rs.caseDim) 1923 exp = Expression.combine(exp, new IntegerExp(rs.caseDim)); 1924 } 1925 else if (tintro && !tret.equals(tintro.nextOf())) 1926 { 1927 exp = exp.implicitCastTo(sc2, tintro.nextOf()); 1928 } 1929 rs.exp = exp; 1930 } 1931 } 1932 if (nrvo_var || returnLabel) 1933 { 1934 scope NrvoWalker nw = new NrvoWalker(); 1935 nw.fd = this; 1936 nw.sc = sc2; 1937 nw.visitStmt(fbody); 1938 } 1939 1940 sc2 = sc2.pop(); 1941 } 1942 1943 Statement freq = frequire; 1944 Statement fens = fensure; 1945 1946 /* Do the semantic analysis on the [in] preconditions and 1947 * [out] postconditions. 1948 */ 1949 if (freq) 1950 { 1951 /* frequire is composed of the [in] contracts 1952 */ 1953 auto sym = new ScopeDsymbol(); 1954 sym.parent = sc2.scopesym; 1955 sym.loc = loc; 1956 sym.endlinnum = endloc.linnum; 1957 sc2 = sc2.push(sym); 1958 sc2.flags = (sc2.flags & ~SCOPEcontract) | SCOPErequire; 1959 1960 // BUG: need to error if accessing out parameters 1961 // BUG: need to treat parameters as const 1962 // BUG: need to disallow returns and throws 1963 // BUG: verify that all in and ref parameters are read 1964 freq = freq.semantic(sc2); 1965 1966 sc2 = sc2.pop(); 1967 1968 if (!global.params.useIn) 1969 freq = null; 1970 } 1971 if (fens) 1972 { 1973 /* fensure is composed of the [out] contracts 1974 */ 1975 if (f.next.ty == Tvoid && outId) 1976 error("void functions have no result"); 1977 1978 if (fensure && f.next.ty != Tvoid) 1979 buildResultVar(scout, f.next); 1980 1981 sc2 = scout; //push 1982 sc2.flags = (sc2.flags & ~SCOPEcontract) | SCOPEensure; 1983 1984 // BUG: need to treat parameters as const 1985 // BUG: need to disallow returns and throws 1986 if (inferRetType && fdensure && (cast(TypeFunction)fdensure.type).parameters) 1987 { 1988 // Return type was unknown in the first semantic pass 1989 Parameter p = (*(cast(TypeFunction)fdensure.type).parameters)[0]; 1990 p.type = f.next; 1991 } 1992 fens = fens.semantic(sc2); 1993 1994 sc2 = sc2.pop(); 1995 1996 if (!global.params.useOut) 1997 fens = null; 1998 } 1999 if (fbody && fbody.isErrorStatement()) 2000 { 2001 } 2002 else 2003 { 2004 auto a = new Statements(); 2005 // Merge in initialization of 'out' parameters 2006 if (parameters) 2007 { 2008 for (size_t i = 0; i < parameters.dim; i++) 2009 { 2010 VarDeclaration v = (*parameters)[i]; 2011 if (v.storage_class & STCout) 2012 { 2013 assert(v._init); 2014 ExpInitializer ie = v._init.isExpInitializer(); 2015 assert(ie); 2016 if (ie.exp.op == TOKconstruct) 2017 ie.exp.op = TOKassign; // construction occured in parameter processing 2018 a.push(new ExpStatement(Loc(), ie.exp)); 2019 } 2020 } 2021 } 2022 2023 if (_arguments) 2024 { 2025 /* Advance to elements[] member of TypeInfo_Tuple with: 2026 * _arguments = v_arguments.elements; 2027 */ 2028 Expression e = new VarExp(Loc(), v_arguments); 2029 e = new DotIdExp(Loc(), e, Id.elements); 2030 e = new ConstructExp(Loc(), _arguments, e); 2031 e = e.semantic(sc2); 2032 2033 _arguments._init = new ExpInitializer(Loc(), e); 2034 auto de = new DeclarationExp(Loc(), _arguments); 2035 a.push(new ExpStatement(Loc(), de)); 2036 } 2037 2038 // Merge contracts together with body into one compound statement 2039 2040 if (freq || fpreinv) 2041 { 2042 if (!freq) 2043 freq = fpreinv; 2044 else if (fpreinv) 2045 freq = new CompoundStatement(Loc(), freq, fpreinv); 2046 2047 a.push(freq); 2048 } 2049 2050 if (fbody) 2051 a.push(fbody); 2052 2053 if (fens || fpostinv) 2054 { 2055 if (!fens) 2056 fens = fpostinv; 2057 else if (fpostinv) 2058 fens = new CompoundStatement(Loc(), fpostinv, fens); 2059 2060 auto ls = new LabelStatement(Loc(), Id.returnLabel, fens); 2061 returnLabel.statement = ls; 2062 a.push(returnLabel.statement); 2063 2064 if (f.next.ty != Tvoid && vresult) 2065 { 2066 // Create: return vresult; 2067 Expression e = new VarExp(Loc(), vresult); 2068 if (tintro) 2069 { 2070 e = e.implicitCastTo(sc, tintro.nextOf()); 2071 e = e.semantic(sc); 2072 } 2073 auto s = new ReturnStatement(Loc(), e); 2074 a.push(s); 2075 } 2076 } 2077 if (isMain() && f.next.ty == Tvoid) 2078 { 2079 // Add a return 0; statement 2080 Statement s = new ReturnStatement(Loc(), new IntegerExp(0)); 2081 a.push(s); 2082 } 2083 2084 Statement sbody = new CompoundStatement(Loc(), a); 2085 2086 /* Append destructor calls for parameters as finally blocks. 2087 */ 2088 if (parameters) 2089 { 2090 foreach (v; *parameters) 2091 { 2092 if (v.storage_class & (STCref | STCout | STClazy)) 2093 continue; 2094 if (v.needsScopeDtor()) 2095 { 2096 // same with ExpStatement.scopeCode() 2097 Statement s = new DtorExpStatement(Loc(), v.edtor, v); 2098 v.storage_class |= STCnodtor; 2099 2100 s = s.semantic(sc2); 2101 2102 bool isnothrow = f.isnothrow & !(flags & FUNCFLAGnothrowInprocess); 2103 int blockexit = s.blockExit(this, isnothrow); 2104 if (f.isnothrow && isnothrow && blockexit & BEthrow) 2105 .error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars()); 2106 if (flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow) 2107 f.isnothrow = false; 2108 2109 if (sbody.blockExit(this, f.isnothrow) == BEfallthru) 2110 sbody = new CompoundStatement(Loc(), sbody, s); 2111 else 2112 sbody = new TryFinallyStatement(Loc(), sbody, s); 2113 } 2114 } 2115 } 2116 // from this point on all possible 'throwers' are checked 2117 flags &= ~FUNCFLAGnothrowInprocess; 2118 2119 if (isSynchronized()) 2120 { 2121 /* Wrap the entire function body in a synchronized statement 2122 */ 2123 ClassDeclaration cd = isThis() ? isThis().isClassDeclaration() : parent.isClassDeclaration(); 2124 if (cd) 2125 { 2126 if (!global.params.is64bit && global.params.isWindows && !isStatic() && !sbody.usesEH() && !global.params.trace) 2127 { 2128 /* The back end uses the "jmonitor" hack for syncing; 2129 * no need to do the sync at this level. 2130 */ 2131 } 2132 else 2133 { 2134 Expression vsync; 2135 if (isStatic()) 2136 { 2137 // The monitor is in the ClassInfo 2138 vsync = new DotIdExp(loc, DsymbolExp.resolve(loc, sc2, cd, false), Id.classinfo); 2139 } 2140 else 2141 { 2142 // 'this' is the monitor 2143 vsync = new VarExp(loc, vthis); 2144 } 2145 sbody = new PeelStatement(sbody); // don't redo semantic() 2146 sbody = new SynchronizedStatement(loc, vsync, sbody); 2147 sbody = sbody.semantic(sc2); 2148 } 2149 } 2150 else 2151 { 2152 error("synchronized function %s must be a member of a class", toChars()); 2153 } 2154 } 2155 2156 // If declaration has no body, don't set sbody to prevent incorrect codegen. 2157 InterfaceDeclaration id = parent.isInterfaceDeclaration(); 2158 if (fbody || id && (fdensure || fdrequire) && isVirtual()) 2159 fbody = sbody; 2160 } 2161 2162 // Fix up forward-referenced gotos 2163 if (gotos) 2164 { 2165 for (size_t i = 0; i < gotos.dim; ++i) 2166 { 2167 (*gotos)[i].checkLabel(); 2168 } 2169 } 2170 2171 if (naked && (fensure || frequire)) 2172 error("naked assembly functions with contracts are not supported"); 2173 2174 sc2.callSuper = 0; 2175 sc2.pop(); 2176 } 2177 2178 if (checkClosure()) 2179 { 2180 // We should be setting errors here instead of relying on the global error count. 2181 //errors = true; 2182 } 2183 2184 /* If function survived being marked as impure, then it is pure 2185 */ 2186 if (flags & FUNCFLAGpurityInprocess) 2187 { 2188 flags &= ~FUNCFLAGpurityInprocess; 2189 if (type == f) 2190 f = cast(TypeFunction)f.copy(); 2191 f.purity = PUREfwdref; 2192 } 2193 2194 if (flags & FUNCFLAGsafetyInprocess) 2195 { 2196 flags &= ~FUNCFLAGsafetyInprocess; 2197 if (type == f) 2198 f = cast(TypeFunction)f.copy(); 2199 f.trust = TRUSTsafe; 2200 } 2201 2202 if (flags & FUNCFLAGnogcInprocess) 2203 { 2204 flags &= ~FUNCFLAGnogcInprocess; 2205 if (type == f) 2206 f = cast(TypeFunction)f.copy(); 2207 f.isnogc = true; 2208 } 2209 2210 flags &= ~FUNCFLAGreturnInprocess; 2211 2212 // reset deco to apply inference result to mangled name 2213 if (f != type) 2214 f.deco = null; 2215 2216 // Do semantic type AFTER pure/nothrow inference. 2217 if (!f.deco && ident != Id.xopEquals && ident != Id.xopCmp) 2218 { 2219 sc = sc.push(); 2220 if (isCtorDeclaration()) // Bugzilla #15665 2221 sc.flags |= SCOPEctor; 2222 sc.stc = 0; 2223 sc.linkage = linkage; // Bugzilla 8496 2224 type = f.semantic(loc, sc); 2225 sc = sc.pop(); 2226 } 2227 2228 /* If this function had instantiated with gagging, error reproduction will be 2229 * done by TemplateInstance::semantic. 2230 * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. 2231 */ 2232 semanticRun = PASSsemantic3done; 2233 semantic3Errors = (global.errors != oldErrors) || (fbody && fbody.isErrorStatement()); 2234 if (type.ty == Terror) 2235 errors = true; 2236 //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); 2237 //fflush(stdout); 2238 } 2239 2240 /**************************************************** 2241 * Resolve forward reference of function signature - 2242 * parameter types, return type, and attributes. 2243 * Returns false if any errors exist in the signature. 2244 */ 2245 final bool functionSemantic() 2246 { 2247 if (!_scope) 2248 return !errors; 2249 2250 if (!originalType) // semantic not yet run 2251 { 2252 TemplateInstance spec = isSpeculative(); 2253 uint olderrs = global.errors; 2254 uint oldgag = global.gag; 2255 if (global.gag && !spec) 2256 global.gag = 0; 2257 semantic(_scope); 2258 global.gag = oldgag; 2259 if (spec && global.errors != olderrs) 2260 spec.errors = (global.errors - olderrs != 0); 2261 if (olderrs != global.errors) // if errors compiling this function 2262 return false; 2263 } 2264 2265 // if inferring return type, sematic3 needs to be run 2266 // - When the function body contains any errors, we cannot assume 2267 // the inferred return type is valid. 2268 // So, the body errors should become the function signature error. 2269 if (inferRetType && type && !type.nextOf()) 2270 return functionSemantic3(); 2271 2272 TemplateInstance ti; 2273 if (isInstantiated() && !isVirtualMethod() && 2274 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) 2275 { 2276 AggregateDeclaration ad = isMember2(); 2277 if (ad && ad.sizeok != SIZEOKdone) 2278 { 2279 /* Currently dmd cannot resolve forward references per methods, 2280 * then setting SIZOKfwd is too conservative and would break existing code. 2281 * So, just stop method attributes inference until ad->semantic() done. 2282 */ 2283 //ad->sizeok = SIZEOKfwd; 2284 } 2285 else 2286 return functionSemantic3() || !errors; 2287 } 2288 2289 if (storage_class & STCinference) 2290 return functionSemantic3() || !errors; 2291 2292 return !errors; 2293 } 2294 2295 /**************************************************** 2296 * Resolve forward reference of function body. 2297 * Returns false if any errors exist in the body. 2298 */ 2299 final bool functionSemantic3() 2300 { 2301 if (semanticRun < PASSsemantic3 && _scope) 2302 { 2303 /* Forward reference - we need to run semantic3 on this function. 2304 * If errors are gagged, and it's not part of a template instance, 2305 * we need to temporarily ungag errors. 2306 */ 2307 TemplateInstance spec = isSpeculative(); 2308 uint olderrs = global.errors; 2309 uint oldgag = global.gag; 2310 if (global.gag && !spec) 2311 global.gag = 0; 2312 semantic3(_scope); 2313 global.gag = oldgag; 2314 2315 // If it is a speculatively-instantiated template, and errors occur, 2316 // we need to mark the template as having errors. 2317 if (spec && global.errors != olderrs) 2318 spec.errors = (global.errors - olderrs != 0); 2319 if (olderrs != global.errors) // if errors compiling this function 2320 return false; 2321 } 2322 2323 return !errors && !semantic3Errors; 2324 } 2325 2326 /**************************************************** 2327 * Check that this function type is properly resolved. 2328 * If not, report "forward reference error" and return true. 2329 */ 2330 final bool checkForwardRef(Loc loc) 2331 { 2332 if (!functionSemantic()) 2333 return true; 2334 2335 /* No deco means the functionSemantic() call could not resolve 2336 * forward referenes in the type of this function. 2337 */ 2338 if (!type.deco) 2339 { 2340 bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3); 2341 .error(loc, "forward reference to %s'%s'", 2342 (inSemantic3 ? "inferred return type of function " : "").ptr, 2343 toChars()); 2344 return true; 2345 } 2346 return false; 2347 } 2348 2349 // called from semantic3 2350 final VarDeclaration declareThis(Scope* sc, AggregateDeclaration ad) 2351 { 2352 if (ad) 2353 { 2354 Type thandle = ad.handleType(); 2355 assert(thandle); 2356 thandle = thandle.addMod(type.mod); 2357 thandle = thandle.addStorageClass(storage_class); 2358 VarDeclaration v = new ThisDeclaration(loc, thandle); 2359 v.storage_class |= STCparameter; 2360 if (thandle.ty == Tstruct) 2361 { 2362 v.storage_class |= STCref; 2363 // if member function is marked 'inout', then 'this' is 'return ref' 2364 if (type.ty == Tfunction && (cast(TypeFunction)type).iswild & 2) 2365 v.storage_class |= STCreturn; 2366 } 2367 if (type.ty == Tfunction && (cast(TypeFunction)type).isreturn) 2368 v.storage_class |= STCreturn; 2369 2370 v.semantic(sc); 2371 if (!sc.insert(v)) 2372 assert(0); 2373 v.parent = this; 2374 return v; 2375 } 2376 if (isNested()) 2377 { 2378 /* The 'this' for a nested function is the link to the 2379 * enclosing function's stack frame. 2380 * Note that nested functions and member functions are disjoint. 2381 */ 2382 VarDeclaration v = new ThisDeclaration(loc, Type.tvoid.pointerTo()); 2383 v.storage_class |= STCparameter; 2384 v.semantic(sc); 2385 if (!sc.insert(v)) 2386 assert(0); 2387 v.parent = this; 2388 return v; 2389 } 2390 return null; 2391 } 2392 2393 override final bool equals(RootObject o) 2394 { 2395 if (this == o) 2396 return true; 2397 2398 Dsymbol s = isDsymbol(o); 2399 if (s) 2400 { 2401 FuncDeclaration fd1 = this; 2402 FuncDeclaration fd2 = s.isFuncDeclaration(); 2403 if (!fd2) 2404 return false; 2405 2406 FuncAliasDeclaration fa1 = fd1.isFuncAliasDeclaration(); 2407 FuncAliasDeclaration fa2 = fd2.isFuncAliasDeclaration(); 2408 if (fa1 && fa2) 2409 { 2410 return fa1.toAliasFunc().equals(fa2.toAliasFunc()) && fa1.hasOverloads == fa2.hasOverloads; 2411 } 2412 2413 if (fa1 && (fd1 = fa1.toAliasFunc()).isUnique() && !fa1.hasOverloads) 2414 fa1 = null; 2415 if (fa2 && (fd2 = fa2.toAliasFunc()).isUnique() && !fa2.hasOverloads) 2416 fa2 = null; 2417 if ((fa1 !is null) != (fa2 !is null)) 2418 return false; 2419 2420 return fd1.toParent().equals(fd2.toParent()) && fd1.ident.equals(fd2.ident) && fd1.type.equals(fd2.type); 2421 } 2422 return false; 2423 } 2424 2425 /**************************************************** 2426 * Determine if 'this' overrides fd. 2427 * Return !=0 if it does. 2428 */ 2429 final int overrides(FuncDeclaration fd) 2430 { 2431 int result = 0; 2432 if (fd.ident == ident) 2433 { 2434 int cov = type.covariant(fd.type); 2435 if (cov) 2436 { 2437 ClassDeclaration cd1 = toParent().isClassDeclaration(); 2438 ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); 2439 if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) 2440 result = 1; 2441 } 2442 } 2443 return result; 2444 } 2445 2446 /************************************************* 2447 * Find index of function in vtbl[0..dim] that 2448 * this function overrides. 2449 * Prefer an exact match to a covariant one. 2450 * Returns: 2451 * -1 didn't find one 2452 * -2 can't determine because of forward references 2453 */ 2454 final int findVtblIndex(Dsymbols* vtbl, int dim) 2455 { 2456 FuncDeclaration mismatch = null; 2457 StorageClass mismatchstc = 0; 2458 int mismatchvi = -1; 2459 int exactvi = -1; 2460 int bestvi = -1; 2461 for (int vi = 0; vi < dim; vi++) 2462 { 2463 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); 2464 if (fdv && fdv.ident == ident) 2465 { 2466 if (type.equals(fdv.type)) // if exact match 2467 { 2468 if (fdv.parent.isClassDeclaration()) 2469 return vi; // no need to look further 2470 2471 if (exactvi >= 0) 2472 { 2473 error("cannot determine overridden function"); 2474 return exactvi; 2475 } 2476 exactvi = vi; 2477 bestvi = vi; 2478 continue; 2479 } 2480 2481 StorageClass stc = 0; 2482 int cov = type.covariant(fdv.type, &stc); 2483 //printf("\tbaseclass cov = %d\n", cov); 2484 switch (cov) 2485 { 2486 case 0: 2487 // types are distinct 2488 break; 2489 2490 case 1: 2491 bestvi = vi; // covariant, but not identical 2492 break; 2493 // keep looking for an exact match 2494 2495 case 2: 2496 mismatchvi = vi; 2497 mismatchstc = stc; 2498 mismatch = fdv; // overrides, but is not covariant 2499 break; 2500 // keep looking for an exact match 2501 2502 case 3: 2503 return -2; // forward references 2504 2505 default: 2506 assert(0); 2507 } 2508 } 2509 } 2510 if (bestvi == -1 && mismatch) 2511 { 2512 //type->print(); 2513 //mismatch->type->print(); 2514 //printf("%s %s\n", type->deco, mismatch->type->deco); 2515 //printf("stc = %llx\n", mismatchstc); 2516 if (mismatchstc) 2517 { 2518 // Fix it by modifying the type to add the storage classes 2519 type = type.addStorageClass(mismatchstc); 2520 bestvi = mismatchvi; 2521 } 2522 } 2523 return bestvi; 2524 } 2525 2526 /********************************* 2527 * If function a function in a base class, 2528 * return that base class. 2529 * Params: 2530 * cd = class that function is in 2531 * Returns: 2532 * base class if overriding, null if not 2533 */ 2534 final BaseClass* overrideInterface() 2535 { 2536 ClassDeclaration cd = parent.isClassDeclaration(); 2537 foreach (b; cd.interfaces) 2538 { 2539 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); 2540 if (v >= 0) 2541 return b; 2542 } 2543 return null; 2544 } 2545 2546 /**************************************************** 2547 * Overload this FuncDeclaration with the new one f. 2548 * Return true if successful; i.e. no conflict. 2549 */ 2550 override bool overloadInsert(Dsymbol s) 2551 { 2552 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars()); 2553 assert(s != this); 2554 AliasDeclaration ad = s.isAliasDeclaration(); 2555 if (ad) 2556 { 2557 if (overnext) 2558 return overnext.overloadInsert(ad); 2559 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance) 2560 { 2561 //printf("\tad = '%s'\n", ad->type->toChars()); 2562 return false; 2563 } 2564 overnext = ad; 2565 //printf("\ttrue: no conflict\n"); 2566 return true; 2567 } 2568 TemplateDeclaration td = s.isTemplateDeclaration(); 2569 if (td) 2570 { 2571 if (!td.funcroot) 2572 td.funcroot = this; 2573 if (overnext) 2574 return overnext.overloadInsert(td); 2575 overnext = td; 2576 return true; 2577 } 2578 FuncDeclaration fd = s.isFuncDeclaration(); 2579 if (!fd) 2580 return false; 2581 2582 version (none) 2583 { 2584 /* Disable this check because: 2585 * const void foo(); 2586 * semantic() isn't run yet on foo(), so the const hasn't been 2587 * applied yet. 2588 */ 2589 if (type) 2590 { 2591 printf("type = %s\n", type.toChars()); 2592 printf("fd->type = %s\n", fd.type.toChars()); 2593 } 2594 // fd->type can be NULL for overloaded constructors 2595 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration()) 2596 { 2597 //printf("\tfalse: conflict %s\n", kind()); 2598 return false; 2599 } 2600 } 2601 2602 if (overnext) 2603 { 2604 td = overnext.isTemplateDeclaration(); 2605 if (td) 2606 fd.overloadInsert(td); 2607 else 2608 return overnext.overloadInsert(fd); 2609 } 2610 overnext = fd; 2611 //printf("\ttrue: no conflict\n"); 2612 return true; 2613 } 2614 2615 /******************************************** 2616 * Find function in overload list that exactly matches t. 2617 */ 2618 final FuncDeclaration overloadExactMatch(Type t) 2619 { 2620 FuncDeclaration fd; 2621 overloadApply(this, (Dsymbol s) 2622 { 2623 auto f = s.isFuncDeclaration(); 2624 if (!f) 2625 return 0; 2626 if (t.equals(f.type)) 2627 { 2628 fd = f; 2629 return 1; 2630 } 2631 2632 /* Allow covariant matches, as long as the return type 2633 * is just a const conversion. 2634 * This allows things like pure functions to match with an impure function type. 2635 */ 2636 if (t.ty == Tfunction) 2637 { 2638 auto tf = cast(TypeFunction)f.type; 2639 if (tf.covariant(t) == 1 && 2640 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCHconst) 2641 { 2642 fd = f; 2643 return 1; 2644 } 2645 } 2646 return 0; 2647 }); 2648 return fd; 2649 } 2650 2651 /******************************************** 2652 * Find function in overload list that matches to the 'this' modifier. 2653 * There's four result types. 2654 * 2655 * 1. If the 'tthis' matches only one candidate, it's an "exact match". 2656 * Returns the function and 'hasOverloads' is set to false. 2657 * eg. If 'tthis" is mutable and there's only one mutable method. 2658 * 2. If there's two or more match candidates, but a candidate function will be 2659 * a "better match". 2660 * Returns the better match function but 'hasOverloads' is set to true. 2661 * eg. If 'tthis' is mutable, and there's both mutable and const methods, 2662 * the mutable method will be a better match. 2663 * 3. If there's two or more match candidates, but there's no better match, 2664 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match". 2665 * eg. If 'tthis' is mutable, and there's two or more mutable methods. 2666 * 4. If there's no candidates, it's "no match" and returns null with error report. 2667 * e.g. If 'tthis' is const but there's no const methods. 2668 */ 2669 final FuncDeclaration overloadModMatch(Loc loc, Type tthis, ref bool hasOverloads) 2670 { 2671 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars()); 2672 Match m; 2673 m.last = MATCHnomatch; 2674 overloadApply(this, (Dsymbol s) 2675 { 2676 auto f = s.isFuncDeclaration(); 2677 if (!f || f == m.lastf) // skip duplicates 2678 return 0; 2679 m.anyf = f; 2680 2681 auto tf = cast(TypeFunction)f.type; 2682 //printf("tf = %s\n", tf->toChars()); 2683 2684 MATCH match; 2685 if (tthis) // non-static functions are preferred than static ones 2686 { 2687 if (f.needThis()) 2688 match = f.isCtorDeclaration() ? MATCHexact : MODmethodConv(tthis.mod, tf.mod); 2689 else 2690 match = MATCHconst; // keep static funciton in overload candidates 2691 } 2692 else // static functions are preferred than non-static ones 2693 { 2694 if (f.needThis()) 2695 match = MATCHconvert; 2696 else 2697 match = MATCHexact; 2698 } 2699 if (match == MATCHnomatch) 2700 return 0; 2701 2702 if (match > m.last) goto LcurrIsBetter; 2703 if (match < m.last) goto LlastIsBetter; 2704 2705 // See if one of the matches overrides the other. 2706 if (m.lastf.overrides(f)) goto LlastIsBetter; 2707 if (f.overrides(m.lastf)) goto LcurrIsBetter; 2708 2709 Lambiguous: 2710 //printf("\tambiguous\n"); 2711 m.nextf = f; 2712 m.count++; 2713 return 0; 2714 2715 LlastIsBetter: 2716 //printf("\tlastbetter\n"); 2717 m.count++; // count up 2718 return 0; 2719 2720 LcurrIsBetter: 2721 //printf("\tisbetter\n"); 2722 if (m.last <= MATCHconvert) 2723 { 2724 // clear last secondary matching 2725 m.nextf = null; 2726 m.count = 0; 2727 } 2728 m.last = match; 2729 m.lastf = f; 2730 m.count++; // count up 2731 return 0; 2732 }); 2733 2734 if (m.count == 1) // exact match 2735 { 2736 hasOverloads = false; 2737 } 2738 else if (m.count > 1) // better or ambiguous match 2739 { 2740 hasOverloads = true; 2741 } 2742 else // no match 2743 { 2744 hasOverloads = true; 2745 auto tf = cast(TypeFunction)this.type; 2746 assert(tthis); 2747 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch 2748 { 2749 OutBuffer thisBuf, funcBuf; 2750 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 2751 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 2752 .error(loc, "%smethod %s is not callable using a %sobject", 2753 funcBuf.peekString(), this.toPrettyChars(), thisBuf.peekString()); 2754 } 2755 } 2756 return m.lastf; 2757 } 2758 2759 /******************************************** 2760 * find function template root in overload list 2761 */ 2762 final TemplateDeclaration findTemplateDeclRoot() 2763 { 2764 FuncDeclaration f = this; 2765 while (f && f.overnext) 2766 { 2767 //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars()); 2768 TemplateDeclaration td = f.overnext.isTemplateDeclaration(); 2769 if (td) 2770 return td; 2771 f = f.overnext.isFuncDeclaration(); 2772 } 2773 return null; 2774 } 2775 2776 /******************************************** 2777 * Returns true if function was declared 2778 * directly or indirectly in a unittest block 2779 */ 2780 final bool inUnittest() 2781 { 2782 Dsymbol f = this; 2783 do 2784 { 2785 if (f.isUnitTestDeclaration()) 2786 return true; 2787 f = f.toParent(); 2788 } 2789 while (f); 2790 return false; 2791 } 2792 2793 /************************************* 2794 * Determine partial specialization order of 'this' vs g. 2795 * This is very similar to TemplateDeclaration::leastAsSpecialized(). 2796 * Returns: 2797 * match 'this' is at least as specialized as g 2798 * 0 g is more specialized than 'this' 2799 */ 2800 final MATCH leastAsSpecialized(FuncDeclaration g) 2801 { 2802 enum LOG_LEASTAS = 0; 2803 static if (LOG_LEASTAS) 2804 { 2805 printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); 2806 printf("%s, %s\n", type.toChars(), g.type.toChars()); 2807 } 2808 2809 /* This works by calling g() with f()'s parameters, and 2810 * if that is possible, then f() is at least as specialized 2811 * as g() is. 2812 */ 2813 2814 TypeFunction tf = cast(TypeFunction)type; 2815 TypeFunction tg = cast(TypeFunction)g.type; 2816 size_t nfparams = Parameter.dim(tf.parameters); 2817 2818 /* If both functions have a 'this' pointer, and the mods are not 2819 * the same and g's is not const, then this is less specialized. 2820 */ 2821 if (needThis() && g.needThis() && tf.mod != tg.mod) 2822 { 2823 if (isCtorDeclaration()) 2824 { 2825 if (!MODimplicitConv(tg.mod, tf.mod)) 2826 return MATCHnomatch; 2827 } 2828 else 2829 { 2830 if (!MODimplicitConv(tf.mod, tg.mod)) 2831 return MATCHnomatch; 2832 } 2833 } 2834 2835 /* Create a dummy array of arguments out of the parameters to f() 2836 */ 2837 Expressions args; 2838 args.setDim(nfparams); 2839 for (size_t u = 0; u < nfparams; u++) 2840 { 2841 Parameter p = Parameter.getNth(tf.parameters, u); 2842 Expression e; 2843 if (p.storageClass & (STCref | STCout)) 2844 { 2845 e = new IdentifierExp(Loc(), p.ident); 2846 e.type = p.type; 2847 } 2848 else 2849 e = p.type.defaultInitLiteral(Loc()); 2850 args[u] = e; 2851 } 2852 2853 MATCH m = tg.callMatch(null, &args, 1); 2854 if (m > MATCHnomatch) 2855 { 2856 /* A variadic parameter list is less specialized than a 2857 * non-variadic one. 2858 */ 2859 if (tf.varargs && !tg.varargs) 2860 goto L1; // less specialized 2861 2862 static if (LOG_LEASTAS) 2863 { 2864 printf(" matches %d, so is least as specialized\n", m); 2865 } 2866 return m; 2867 } 2868 L1: 2869 static if (LOG_LEASTAS) 2870 { 2871 printf(" doesn't match, so is not as specialized\n"); 2872 } 2873 return MATCHnomatch; 2874 } 2875 2876 /******************************** 2877 * Labels are in a separate scope, one per function. 2878 */ 2879 final LabelDsymbol searchLabel(Identifier ident) 2880 { 2881 Dsymbol s; 2882 if (!labtab) 2883 labtab = new DsymbolTable(); // guess we need one 2884 2885 s = labtab.lookup(ident); 2886 if (!s) 2887 { 2888 s = new LabelDsymbol(ident); 2889 labtab.insert(s); 2890 } 2891 return cast(LabelDsymbol)s; 2892 } 2893 2894 /***************************************** 2895 * Determine lexical level difference from 'this' to nested function 'fd'. 2896 * Error if this cannot call fd. 2897 * Returns: 2898 * 0 same level 2899 * >0 decrease nesting by number 2900 * -1 increase nesting by 1 (fd is nested within 'this') 2901 * -2 error 2902 */ 2903 final int getLevel(Loc loc, Scope* sc, FuncDeclaration fd) 2904 { 2905 int level; 2906 Dsymbol s; 2907 Dsymbol fdparent; 2908 2909 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars()); 2910 fdparent = fd.toParent2(); 2911 if (fdparent == this) 2912 return -1; 2913 s = this; 2914 level = 0; 2915 while (fd != s && fdparent != s.toParent2()) 2916 { 2917 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars()); 2918 FuncDeclaration thisfd = s.isFuncDeclaration(); 2919 if (thisfd) 2920 { 2921 if (!thisfd.isNested() && !thisfd.vthis && !sc.intypeof) 2922 goto Lerr; 2923 } 2924 else 2925 { 2926 AggregateDeclaration thiscd = s.isAggregateDeclaration(); 2927 if (thiscd) 2928 { 2929 /* AggregateDeclaration::isNested returns true only when 2930 * it has a hidden pointer. 2931 * But, calling the function belongs unrelated lexical scope 2932 * is still allowed inside typeof. 2933 * 2934 * struct Map(alias fun) { 2935 * typeof({ return fun(); }) RetType; 2936 * // No member function makes Map struct 'not nested'. 2937 * } 2938 */ 2939 if (!thiscd.isNested() && !sc.intypeof) 2940 goto Lerr; 2941 } 2942 else 2943 goto Lerr; 2944 } 2945 2946 s = s.toParent2(); 2947 assert(s); 2948 level++; 2949 } 2950 return level; 2951 2952 Lerr: 2953 // Don't give error if in template constraint 2954 if (!(sc.flags & SCOPEconstraint)) 2955 { 2956 const(char)* xstatic = isStatic() ? "static " : ""; 2957 // better diagnostics for static functions 2958 .error(loc, "%s%s %s cannot access frame of function %s", xstatic, kind(), toPrettyChars(), fd.toPrettyChars()); 2959 return -2; 2960 } 2961 return 1; 2962 } 2963 2964 override const(char)* toPrettyChars(bool QualifyTypes = false) 2965 { 2966 if (isMain()) 2967 return "D main"; 2968 else 2969 return Dsymbol.toPrettyChars(QualifyTypes); 2970 } 2971 2972 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ 2973 final const(char)* toFullSignature() 2974 { 2975 OutBuffer buf; 2976 functionToBufferWithIdent(cast(TypeFunction)type, &buf, toChars()); 2977 return buf.extractString(); 2978 } 2979 2980 final bool isMain() 2981 { 2982 return ident == Id.main && linkage != LINKc && !isMember() && !isNested(); 2983 } 2984 2985 final bool isCMain() 2986 { 2987 return ident == Id.main && linkage == LINKc && !isMember() && !isNested(); 2988 } 2989 2990 final bool isWinMain() 2991 { 2992 //printf("FuncDeclaration::isWinMain() %s\n", toChars()); 2993 version (none) 2994 { 2995 bool x = ident == Id.WinMain && linkage != LINKc && !isMember(); 2996 printf("%s\n", x ? "yes" : "no"); 2997 return x; 2998 } 2999 else 3000 { 3001 return ident == Id.WinMain && linkage != LINKc && !isMember(); 3002 } 3003 } 3004 3005 final bool isDllMain() 3006 { 3007 return ident == Id.DllMain && linkage != LINKc && !isMember(); 3008 } 3009 3010 override final bool isExport() 3011 { 3012 return protection.kind == PROTexport; 3013 } 3014 3015 override final bool isImportedSymbol() 3016 { 3017 //printf("isImportedSymbol()\n"); 3018 //printf("protection = %d\n", protection); 3019 return (protection.kind == PROTexport) && !fbody; 3020 } 3021 3022 override final bool isCodeseg() 3023 { 3024 return true; // functions are always in the code segment 3025 } 3026 3027 override final bool isOverloadable() 3028 { 3029 return true; // functions can be overloaded 3030 } 3031 3032 /********************************** 3033 * Decide if attributes for this function can be inferred from examining 3034 * the function body. 3035 * Returns: 3036 * true if can 3037 */ 3038 private final bool canInferAttributes(Scope* sc) 3039 { 3040 if (!fbody) 3041 return false; 3042 3043 if (isVirtualMethod()) 3044 return false; // since they may be overridden 3045 3046 if (sc.func && 3047 /********** this is for backwards compatibility for the moment ********/ 3048 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated())) 3049 return true; 3050 3051 if (isFuncLiteralDeclaration() || // externs are not possible with literals 3052 (storage_class & STCinference) || // do attribute inference 3053 (inferRetType && !isCtorDeclaration())) 3054 return true; 3055 3056 if (isInstantiated()) 3057 { 3058 TemplateInstance ti = parent.isTemplateInstance(); 3059 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident) 3060 return true; 3061 } 3062 3063 return false; 3064 } 3065 3066 /***************************************** 3067 * Initialize for inferring the attributes of this function. 3068 */ 3069 private final void initInferAttributes() 3070 { 3071 assert(type.ty == Tfunction); 3072 TypeFunction tf = cast(TypeFunction)type; 3073 if (tf.purity == PUREimpure) // purity not specified 3074 flags |= FUNCFLAGpurityInprocess; 3075 3076 if (tf.trust == TRUSTdefault) 3077 flags |= FUNCFLAGsafetyInprocess; 3078 3079 if (!tf.isnothrow) 3080 flags |= FUNCFLAGnothrowInprocess; 3081 3082 if (!tf.isnogc) 3083 flags |= FUNCFLAGnogcInprocess; 3084 3085 if (!isVirtual() || introducing) 3086 flags |= FUNCFLAGreturnInprocess; 3087 } 3088 3089 final PURE isPure() 3090 { 3091 //printf("FuncDeclaration::isPure() '%s'\n", toChars()); 3092 assert(type.ty == Tfunction); 3093 TypeFunction tf = cast(TypeFunction)type; 3094 if (flags & FUNCFLAGpurityInprocess) 3095 setImpure(); 3096 if (tf.purity == PUREfwdref) 3097 tf.purityLevel(); 3098 PURE purity = tf.purity; 3099 if (purity > PUREweak && isNested()) 3100 purity = PUREweak; 3101 if (purity > PUREweak && needThis()) 3102 { 3103 // The attribute of the 'this' reference affects purity strength 3104 if (type.mod & MODimmutable) 3105 { 3106 } 3107 else if (type.mod & (MODconst | MODwild) && purity >= PUREconst) 3108 purity = PUREconst; 3109 else 3110 purity = PUREweak; 3111 } 3112 tf.purity = purity; 3113 // ^ This rely on the current situation that every FuncDeclaration has a 3114 // unique TypeFunction. 3115 return purity; 3116 } 3117 3118 final PURE isPureBypassingInference() 3119 { 3120 if (flags & FUNCFLAGpurityInprocess) 3121 return PUREfwdref; 3122 else 3123 return isPure(); 3124 } 3125 3126 /************************************** 3127 * The function is doing something impure, 3128 * so mark it as impure. 3129 * If there's a purity error, return true. 3130 */ 3131 final bool setImpure() 3132 { 3133 if (flags & FUNCFLAGpurityInprocess) 3134 { 3135 flags &= ~FUNCFLAGpurityInprocess; 3136 if (fes) 3137 fes.func.setImpure(); 3138 } 3139 else if (isPure()) 3140 return true; 3141 return false; 3142 } 3143 3144 final bool isSafe() 3145 { 3146 assert(type.ty == Tfunction); 3147 if (flags & FUNCFLAGsafetyInprocess) 3148 setUnsafe(); 3149 return (cast(TypeFunction)type).trust == TRUSTsafe; 3150 } 3151 3152 final bool isSafeBypassingInference() 3153 { 3154 return !(flags & FUNCFLAGsafetyInprocess) && isSafe(); 3155 } 3156 3157 final bool isTrusted() 3158 { 3159 assert(type.ty == Tfunction); 3160 if (flags & FUNCFLAGsafetyInprocess) 3161 setUnsafe(); 3162 return (cast(TypeFunction)type).trust == TRUSTtrusted; 3163 } 3164 3165 /************************************** 3166 * The function is doing something unsave, 3167 * so mark it as unsafe. 3168 * If there's a safe error, return true. 3169 */ 3170 final bool setUnsafe() 3171 { 3172 if (flags & FUNCFLAGsafetyInprocess) 3173 { 3174 flags &= ~FUNCFLAGsafetyInprocess; 3175 (cast(TypeFunction)type).trust = TRUSTsystem; 3176 if (fes) 3177 fes.func.setUnsafe(); 3178 } 3179 else if (isSafe()) 3180 return true; 3181 return false; 3182 } 3183 3184 final bool isNogc() 3185 { 3186 assert(type.ty == Tfunction); 3187 if (flags & FUNCFLAGnogcInprocess) 3188 setGC(); 3189 return (cast(TypeFunction)type).isnogc; 3190 } 3191 3192 final bool isNogcBypassingInference() 3193 { 3194 return !(flags & FUNCFLAGnogcInprocess) && isNogc(); 3195 } 3196 3197 /************************************** 3198 * The function is doing something that may allocate with the GC, 3199 * so mark it as not nogc (not no-how). 3200 * Returns: 3201 * true if function is marked as @nogc, meaning a user error occurred 3202 */ 3203 final bool setGC() 3204 { 3205 if (flags & FUNCFLAGnogcInprocess) 3206 { 3207 flags &= ~FUNCFLAGnogcInprocess; 3208 (cast(TypeFunction)type).isnogc = false; 3209 if (fes) 3210 fes.func.setGC(); 3211 } 3212 else if (isNogc()) 3213 return true; 3214 return false; 3215 } 3216 3217 final void printGCUsage(Loc loc, const(char)* warn) 3218 { 3219 if (!global.params.vgc) 3220 return; 3221 3222 Module m = getModule(); 3223 if (m && m.isRoot() && !inUnittest()) 3224 { 3225 fprintf(global.stdmsg, "%s: vgc: %s\n", loc.toChars(), warn); 3226 } 3227 } 3228 3229 /******************************************** 3230 * Returns true if the function return value has no indirection 3231 * which comes from the parameters. 3232 */ 3233 final bool isolateReturn() 3234 { 3235 assert(type.ty == Tfunction); 3236 TypeFunction tf = cast(TypeFunction)type; 3237 assert(tf.next); 3238 3239 Type treti = tf.next; 3240 treti = tf.isref ? treti : getIndirection(treti); 3241 if (!treti) 3242 return true; // target has no mutable indirection 3243 return parametersIntersect(treti); 3244 } 3245 3246 /******************************************** 3247 * Returns true if an object typed t can have indirections 3248 * which come from the parameters. 3249 */ 3250 final bool parametersIntersect(Type t) 3251 { 3252 assert(t); 3253 if (!isPureBypassingInference() || isNested()) 3254 return false; 3255 3256 assert(type.ty == Tfunction); 3257 TypeFunction tf = cast(TypeFunction)type; 3258 3259 //printf("parametersIntersect(%s) t = %s\n", tf->toChars(), t->toChars()); 3260 3261 size_t dim = Parameter.dim(tf.parameters); 3262 for (size_t i = 0; i < dim; i++) 3263 { 3264 Parameter fparam = Parameter.getNth(tf.parameters, i); 3265 if (!fparam.type) 3266 continue; 3267 Type tprmi = (fparam.storageClass & (STClazy | STCout | STCref)) ? fparam.type : getIndirection(fparam.type); 3268 if (!tprmi) 3269 continue; // there is no mutable indirection 3270 3271 //printf("\t[%d] tprmi = %d %s\n", i, tprmi->ty, tprmi->toChars()); 3272 if (traverseIndirections(tprmi, t)) 3273 return false; 3274 } 3275 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis()) 3276 { 3277 Type tthis = ad.getType().addMod(tf.mod); 3278 //printf("\ttthis = %s\n", tthis->toChars()); 3279 if (traverseIndirections(tthis, t)) 3280 return false; 3281 } 3282 3283 return true; 3284 } 3285 3286 /**************************************** 3287 * Determine if function needs a static frame pointer. 3288 * Returns: 3289 * `true` if function is really nested within other function. 3290 * Contracts: 3291 * If isNested() returns true, isThis() should return false. 3292 */ 3293 bool isNested() 3294 { 3295 auto f = toAliasFunc(); 3296 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars()); 3297 return ((f.storage_class & STCstatic) == 0) && 3298 (f.linkage == LINKd) && 3299 (f.toParent2().isFuncDeclaration() !is null); 3300 } 3301 3302 /**************************************** 3303 * Determine if function is a non-static member function 3304 * that has an implicit 'this' expression. 3305 * Returns: 3306 * The aggregate it is a member of, or null. 3307 * Contracts: 3308 * If isThis() returns true, isNested() should return false. 3309 */ 3310 override AggregateDeclaration isThis() 3311 { 3312 //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); 3313 auto ad = (storage_class & STCstatic) ? null : isMember2(); 3314 //printf("-FuncDeclaration::isThis() %p\n", ad); 3315 return ad; 3316 } 3317 3318 override final bool needThis() 3319 { 3320 //printf("FuncDeclaration::needThis() '%s'\n", toChars()); 3321 return toAliasFunc().isThis() !is null; 3322 } 3323 3324 // Determine if a function is pedantically virtual 3325 final bool isVirtualMethod() 3326 { 3327 if (toAliasFunc() != this) 3328 return toAliasFunc().isVirtualMethod(); 3329 3330 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); 3331 if (!isVirtual()) 3332 return false; 3333 // If it's a final method, and does not override anything, then it is not virtual 3334 if (isFinalFunc() && foverrides.dim == 0) 3335 { 3336 return false; 3337 } 3338 return true; 3339 } 3340 3341 // Determine if function goes into virtual function pointer table 3342 bool isVirtual() 3343 { 3344 if (toAliasFunc() != this) 3345 return toAliasFunc().isVirtual(); 3346 3347 Dsymbol p = toParent(); 3348 version (none) 3349 { 3350 printf("FuncDeclaration::isVirtual(%s)\n", toChars()); 3351 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); 3352 printf("result is %d\n", isMember() && !(isStatic() || protection == PROTprivate || protection == PROTpackage) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc())); 3353 } 3354 return isMember() && !(isStatic() || protection.kind == PROTprivate || protection.kind == PROTpackage) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()); 3355 } 3356 3357 bool isFinalFunc() 3358 { 3359 if (toAliasFunc() != this) 3360 return toAliasFunc().isFinalFunc(); 3361 3362 ClassDeclaration cd; 3363 version (none) 3364 { 3365 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal()); 3366 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STCfinal)); 3367 printf("result is %d\n", isMember() && (Declaration.isFinal() || ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STCfinal))); 3368 if (cd) 3369 printf("\tmember of %s\n", cd.toChars()); 3370 } 3371 return isMember() && (Declaration.isFinal() || ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STCfinal)); 3372 } 3373 3374 bool addPreInvariant() 3375 { 3376 AggregateDeclaration ad = isThis(); 3377 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 3378 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants && (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) && !naked); 3379 } 3380 3381 bool addPostInvariant() 3382 { 3383 AggregateDeclaration ad = isThis(); 3384 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 3385 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants && (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) && !naked); 3386 } 3387 3388 override const(char)* kind() const 3389 { 3390 return generated ? "generated function" : "function"; 3391 } 3392 3393 /******************************************** 3394 * If there are no overloads of function f, return that function, 3395 * otherwise return NULL. 3396 */ 3397 final FuncDeclaration isUnique() 3398 { 3399 FuncDeclaration result = null; 3400 overloadApply(this, (Dsymbol s) 3401 { 3402 auto f = s.isFuncDeclaration(); 3403 if (!f) 3404 return 0; 3405 if (result) 3406 { 3407 result = null; 3408 return 1; // ambiguous, done 3409 } 3410 else 3411 { 3412 result = f; 3413 return 0; 3414 } 3415 }); 3416 return result; 3417 } 3418 3419 /********************************************* 3420 * In the current function, we are calling 'this' function. 3421 * 1. Check to see if the current function can call 'this' function, issue error if not. 3422 * 2. If the current function is not the parent of 'this' function, then add 3423 * the current function to the list of siblings of 'this' function. 3424 * 3. If the current function is a literal, and it's accessing an uplevel scope, 3425 * then mark it as a delegate. 3426 * Returns true if error occurs. 3427 */ 3428 final bool checkNestedReference(Scope* sc, Loc loc) 3429 { 3430 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars()); 3431 3432 if (auto fld = this.isFuncLiteralDeclaration()) 3433 { 3434 if (fld.tok == TOKreserved) 3435 { 3436 fld.tok = TOKfunction; 3437 fld.vthis = null; 3438 } 3439 } 3440 3441 if (!parent || parent == sc.parent) 3442 return false; 3443 if (ident == Id.require || ident == Id.ensure) 3444 return false; 3445 if (!isThis() && !isNested()) 3446 return false; 3447 3448 // The current function 3449 FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); 3450 if (!fdthis) 3451 return false; // out of function scope 3452 3453 Dsymbol p = toParent2(); 3454 3455 // Function literals from fdthis to p must be delegates 3456 checkNestedRef(fdthis, p); 3457 3458 if (isNested()) 3459 { 3460 // The function that this function is in 3461 FuncDeclaration fdv = p.isFuncDeclaration(); 3462 if (!fdv) 3463 return false; 3464 if (fdv == fdthis) 3465 return false; 3466 3467 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars()); 3468 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars()); 3469 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars()); 3470 3471 // Add this function to the list of those which called us 3472 if (fdthis != this) 3473 { 3474 bool found = false; 3475 for (size_t i = 0; i < siblingCallers.dim; ++i) 3476 { 3477 if (siblingCallers[i] == fdthis) 3478 found = true; 3479 } 3480 if (!found) 3481 { 3482 //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); 3483 if (!sc.intypeof && !(sc.flags & SCOPEcompile)) 3484 siblingCallers.push(fdthis); 3485 } 3486 } 3487 3488 int lv = fdthis.getLevel(loc, sc, fdv); 3489 if (lv == -2) 3490 return true; // error 3491 if (lv == -1) 3492 return false; // downlevel call 3493 if (lv == 0) 3494 return false; // same level call 3495 3496 // Uplevel call 3497 } 3498 return false; 3499 } 3500 3501 /******************************* 3502 * Look at all the variables in this function that are referenced 3503 * by nested functions, and determine if a closure needs to be 3504 * created for them. 3505 */ 3506 final bool needsClosure() 3507 { 3508 /* Need a closure for all the closureVars[] if any of the 3509 * closureVars[] are accessed by a 3510 * function that escapes the scope of this function. 3511 * We take the conservative approach and decide that a function needs 3512 * a closure if it: 3513 * 1) is a virtual function 3514 * 2) has its address taken 3515 * 3) has a parent that escapes 3516 * 4) calls another nested function that needs a closure 3517 * -or- 3518 * 5) this function returns a local struct/class 3519 * 3520 * Note that since a non-virtual function can be called by 3521 * a virtual one, if that non-virtual function accesses a closure 3522 * var, the closure still has to be taken. Hence, we check for isThis() 3523 * instead of isVirtual(). (thanks to David Friedman) 3524 */ 3525 3526 //printf("FuncDeclaration::needsClosure() %s\n", toChars()); 3527 3528 if (requiresClosure) 3529 goto Lyes; 3530 3531 for (size_t i = 0; i < closureVars.dim; i++) 3532 { 3533 VarDeclaration v = closureVars[i]; 3534 //printf("\tv = %s\n", v->toChars()); 3535 3536 for (size_t j = 0; j < v.nestedrefs.dim; j++) 3537 { 3538 FuncDeclaration f = v.nestedrefs[j]; 3539 assert(f != this); 3540 3541 //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); 3542 3543 /* Look to see if f escapes. We consider all parents of f within 3544 * this, and also all siblings which call f; if any of them escape, 3545 * so does f. 3546 * Mark all affected functions as requiring closures. 3547 */ 3548 for (Dsymbol s = f; s && s != this; s = s.parent) 3549 { 3550 FuncDeclaration fx = s.isFuncDeclaration(); 3551 if (!fx) 3552 continue; 3553 if (fx.isThis() || fx.tookAddressOf) 3554 { 3555 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx->toChars(), fx->isVirtual(), fx->isThis(), fx->tookAddressOf); 3556 3557 /* Mark as needing closure any functions between this and f 3558 */ 3559 markAsNeedingClosure((fx == f) ? fx.parent : fx, this); 3560 3561 requiresClosure = true; 3562 } 3563 3564 /* We also need to check if any sibling functions that 3565 * called us, have escaped. This is recursive: we need 3566 * to check the callers of our siblings. 3567 */ 3568 if (checkEscapingSiblings(fx, this)) 3569 requiresClosure = true; 3570 3571 /* Bugzilla 12406: Iterate all closureVars to mark all descendant 3572 * nested functions that access to the closing context of this funciton. 3573 */ 3574 } 3575 } 3576 } 3577 if (requiresClosure) 3578 goto Lyes; 3579 3580 /* Look for case (5) 3581 */ 3582 if (closureVars.dim) 3583 { 3584 assert(type.ty == Tfunction); 3585 Type tret = (cast(TypeFunction)type).next; 3586 assert(tret); 3587 tret = tret.toBasetype(); 3588 //printf("\t\treturning %s\n", tret->toChars()); 3589 if (tret.ty == Tclass || tret.ty == Tstruct) 3590 { 3591 Dsymbol st = tret.toDsymbol(null); 3592 //printf("\t\treturning class/struct %s\n", tret->toChars()); 3593 for (Dsymbol s = st.parent; s; s = s.parent) 3594 { 3595 //printf("\t\t\tparent = %s %s\n", s->kind(), s->toChars()); 3596 if (s == this) 3597 { 3598 //printf("\t\treturning local %s\n", st->toChars()); 3599 goto Lyes; 3600 } 3601 } 3602 } 3603 } 3604 3605 return false; 3606 3607 Lyes: 3608 //printf("\tneeds closure\n"); 3609 return true; 3610 } 3611 3612 /*********************************************** 3613 * Check that the function contains any closure. 3614 * If it's @nogc, report suitable errors. 3615 * This is mostly consistent with FuncDeclaration::needsClosure(). 3616 * 3617 * Returns: 3618 * true if any errors occur. 3619 */ 3620 final bool checkClosure() 3621 { 3622 if (!needsClosure()) 3623 return false; 3624 3625 if (setGC()) 3626 { 3627 error("is @nogc yet allocates closures with the GC"); 3628 if (global.gag) // need not report supplemental errors 3629 return true; 3630 } 3631 else 3632 { 3633 printGCUsage(loc, "using closure causes GC allocation"); 3634 return false; 3635 } 3636 3637 FuncDeclarations a; 3638 foreach (v; closureVars) 3639 { 3640 foreach (f; v.nestedrefs) 3641 { 3642 assert(f !is this); 3643 3644 LcheckAncestorsOfANestedRef: 3645 for (Dsymbol s = f; s && s !is this; s = s.parent) 3646 { 3647 auto fx = s.isFuncDeclaration(); 3648 if (!fx) 3649 continue; 3650 if (fx.isThis() || 3651 fx.tookAddressOf || 3652 checkEscapingSiblings(fx, this)) 3653 { 3654 foreach (f2; a) 3655 { 3656 if (f2 == f) 3657 break LcheckAncestorsOfANestedRef; 3658 } 3659 a.push(f); 3660 .errorSupplemental(f.loc, "%s closes over variable %s at %s", 3661 f.toPrettyChars(), v.toChars(), v.loc.toChars()); 3662 break LcheckAncestorsOfANestedRef; 3663 } 3664 } 3665 } 3666 } 3667 3668 return true; 3669 } 3670 3671 /*********************************************** 3672 * Determine if function's variables are referenced by a function 3673 * nested within it. 3674 */ 3675 final bool hasNestedFrameRefs() 3676 { 3677 if (closureVars.dim) 3678 return true; 3679 3680 /* If a virtual function has contracts, assume its variables are referenced 3681 * by those contracts, even if they aren't. Because they might be referenced 3682 * by the overridden or overriding function's contracts. 3683 * This can happen because frequire and fensure are implemented as nested functions, 3684 * and they can be called directly by an overriding function and the overriding function's 3685 * context had better match, or Bugzilla 7335 will bite. 3686 */ 3687 if (fdrequire || fdensure) 3688 return true; 3689 3690 if (foverrides.dim && isVirtualMethod()) 3691 { 3692 for (size_t i = 0; i < foverrides.dim; i++) 3693 { 3694 FuncDeclaration fdv = foverrides[i]; 3695 if (fdv.hasNestedFrameRefs()) 3696 return true; 3697 } 3698 } 3699 return false; 3700 } 3701 3702 /**************************************************** 3703 * Declare result variable lazily. 3704 */ 3705 final void buildResultVar(Scope* sc, Type tret) 3706 { 3707 if (!vresult) 3708 { 3709 Loc loc = fensure ? fensure.loc : this.loc; 3710 3711 /* If inferRetType is true, tret may not be a correct return type yet. 3712 * So, in here it may be a temporary type for vresult, and after 3713 * fbody->semantic() running, vresult->type might be modified. 3714 */ 3715 vresult = new VarDeclaration(loc, tret, outId ? outId : Id.result, null); 3716 vresult.storage_class |= STCnodtor; 3717 3718 if (outId == Id.result) 3719 vresult.storage_class |= STCtemp; 3720 if (!isVirtual()) 3721 vresult.storage_class |= STCconst; 3722 vresult.storage_class |= STCresult; 3723 3724 // set before the semantic() for checkNestedReference() 3725 vresult.parent = this; 3726 } 3727 3728 if (sc && vresult.semanticRun == PASSinit) 3729 { 3730 assert(type.ty == Tfunction); 3731 TypeFunction tf = cast(TypeFunction)type; 3732 if (tf.isref) 3733 vresult.storage_class |= STCref; 3734 vresult.type = tret; 3735 3736 vresult.semantic(sc); 3737 3738 if (!sc.insert(vresult)) 3739 error("out result %s is already defined", vresult.toChars()); 3740 assert(vresult.parent == this); 3741 } 3742 } 3743 3744 /**************************************************** 3745 * Merge into this function the 'in' contracts of all it overrides. 3746 * 'in's are OR'd together, i.e. only one of them needs to pass. 3747 */ 3748 final Statement mergeFrequire(Statement sf) 3749 { 3750 /* If a base function and its override both have an IN contract, then 3751 * only one of them needs to succeed. This is done by generating: 3752 * 3753 * void derived.in() { 3754 * try { 3755 * base.in(); 3756 * } 3757 * catch () { 3758 * ... body of derived.in() ... 3759 * } 3760 * } 3761 * 3762 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid. 3763 * If base.in() throws, then derived.in()'s body is executed. 3764 */ 3765 3766 /* Implementing this is done by having the overriding function call 3767 * nested functions (the fdrequire functions) nested inside the overridden 3768 * function. This requires that the stack layout of the calling function's 3769 * parameters and 'this' pointer be in the same place (as the nested 3770 * function refers to them). 3771 * This is easy for the parameters, as they are all on the stack in the same 3772 * place by definition, since it's an overriding function. The problem is 3773 * getting the 'this' pointer in the same place, since it is a local variable. 3774 * We did some hacks in the code generator to make this happen: 3775 * 1. always generate exception handler frame, or at least leave space for it 3776 * in the frame (Windows 32 SEH only) 3777 * 2. always generate an EBP style frame 3778 * 3. since 'this' is passed in a register that is subsequently copied into 3779 * a stack local, allocate that local immediately following the exception 3780 * handler block, so it is always at the same offset from EBP. 3781 */ 3782 for (size_t i = 0; i < foverrides.dim; i++) 3783 { 3784 FuncDeclaration fdv = foverrides[i]; 3785 3786 /* The semantic pass on the contracts of the overridden functions must 3787 * be completed before code generation occurs (bug 3602). 3788 */ 3789 if (fdv.fdrequire && fdv.fdrequire.semanticRun != PASSsemantic3done) 3790 { 3791 assert(fdv._scope); 3792 Scope* sc = fdv._scope.push(); 3793 sc.stc &= ~STCoverride; 3794 fdv.semantic3(sc); 3795 sc.pop(); 3796 } 3797 3798 sf = fdv.mergeFrequire(sf); 3799 if (sf && fdv.fdrequire) 3800 { 3801 //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); 3802 /* Make the call: 3803 * try { __require(); } 3804 * catch (Throwable) { frequire; } 3805 */ 3806 Expression eresult = null; 3807 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), eresult); 3808 Statement s2 = new ExpStatement(loc, e); 3809 3810 auto c = new Catch(loc, getThrowable(), null, sf); 3811 c.internalCatch = true; 3812 auto catches = new Catches(); 3813 catches.push(c); 3814 sf = new TryCatchStatement(loc, s2, catches); 3815 } 3816 else 3817 return null; 3818 } 3819 return sf; 3820 } 3821 3822 /**************************************************** 3823 * Merge into this function the 'out' contracts of all it overrides. 3824 * 'out's are AND'd together, i.e. all of them need to pass. 3825 */ 3826 final Statement mergeFensure(Statement sf, Identifier oid) 3827 { 3828 /* Same comments as for mergeFrequire(), except that we take care 3829 * of generating a consistent reference to the 'result' local by 3830 * explicitly passing 'result' to the nested function as a reference 3831 * argument. 3832 * This won't work for the 'this' parameter as it would require changing 3833 * the semantic code for the nested function so that it looks on the parameter 3834 * list for the 'this' pointer, something that would need an unknown amount 3835 * of tweaking of various parts of the compiler that I'd rather leave alone. 3836 */ 3837 for (size_t i = 0; i < foverrides.dim; i++) 3838 { 3839 FuncDeclaration fdv = foverrides[i]; 3840 3841 /* The semantic pass on the contracts of the overridden functions must 3842 * be completed before code generation occurs (bug 3602 and 5230). 3843 */ 3844 if (fdv.fdensure && fdv.fdensure.semanticRun != PASSsemantic3done) 3845 { 3846 assert(fdv._scope); 3847 Scope* sc = fdv._scope.push(); 3848 sc.stc &= ~STCoverride; 3849 fdv.semantic3(sc); 3850 sc.pop(); 3851 } 3852 3853 sf = fdv.mergeFensure(sf, oid); 3854 if (fdv.fdensure) 3855 { 3856 //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); 3857 // Make the call: __ensure(result) 3858 Expression eresult = null; 3859 if (outId) 3860 { 3861 eresult = new IdentifierExp(loc, oid); 3862 3863 Type t1 = fdv.type.nextOf().toBasetype(); 3864 Type t2 = this.type.nextOf().toBasetype(); 3865 if (t1.isBaseOf(t2, null)) 3866 { 3867 /* Making temporary reference variable is necessary 3868 * in covariant return. 3869 * See bugzilla 5204 and 10479. 3870 */ 3871 auto ei = new ExpInitializer(Loc(), eresult); 3872 auto v = new VarDeclaration(Loc(), t1, Identifier.generateId("__covres"), ei); 3873 v.storage_class |= STCtemp; 3874 auto de = new DeclarationExp(Loc(), v); 3875 auto ve = new VarExp(Loc(), v); 3876 eresult = new CommaExp(Loc(), de, ve); 3877 } 3878 } 3879 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), eresult); 3880 Statement s2 = new ExpStatement(loc, e); 3881 3882 if (sf) 3883 { 3884 sf = new CompoundStatement(sf.loc, s2, sf); 3885 } 3886 else 3887 sf = s2; 3888 } 3889 } 3890 return sf; 3891 } 3892 3893 /********************************************* 3894 * Return the function's parameter list, and whether 3895 * it is variadic or not. 3896 */ 3897 final Parameters* getParameters(int* pvarargs) 3898 { 3899 Parameters* fparameters = null; 3900 int fvarargs = 0; 3901 3902 if (type) 3903 { 3904 assert(type.ty == Tfunction); 3905 TypeFunction fdtype = cast(TypeFunction)type; 3906 fparameters = fdtype.parameters; 3907 fvarargs = fdtype.varargs; 3908 } 3909 if (pvarargs) 3910 *pvarargs = fvarargs; 3911 3912 return fparameters; 3913 } 3914 3915 /********************************** 3916 * Generate a FuncDeclaration for a runtime library function. 3917 */ 3918 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) 3919 { 3920 return genCfunc(fparams, treturn, Identifier.idPool(name, strlen(name)), stc); 3921 } 3922 3923 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) 3924 { 3925 FuncDeclaration fd; 3926 TypeFunction tf; 3927 Dsymbol s; 3928 static __gshared DsymbolTable st = null; 3929 3930 //printf("genCfunc(name = '%s')\n", id->toChars()); 3931 //printf("treturn\n\t"); treturn->print(); 3932 3933 // See if already in table 3934 if (!st) 3935 st = new DsymbolTable(); 3936 s = st.lookup(id); 3937 if (s) 3938 { 3939 fd = s.isFuncDeclaration(); 3940 assert(fd); 3941 assert(fd.type.nextOf().equals(treturn)); 3942 } 3943 else 3944 { 3945 tf = new TypeFunction(fparams, treturn, 0, LINKc, stc); 3946 fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf); 3947 fd.protection = Prot(PROTpublic); 3948 fd.linkage = LINKc; 3949 3950 st.insert(fd); 3951 } 3952 return fd; 3953 } 3954 3955 override final inout(FuncDeclaration) isFuncDeclaration() inout 3956 { 3957 return this; 3958 } 3959 3960 FuncDeclaration toAliasFunc() 3961 { 3962 return this; 3963 } 3964 3965 override void accept(Visitor v) 3966 { 3967 v.visit(this); 3968 } 3969 } 3970 3971 /******************************************************** 3972 * Generate Expression to call the invariant. 3973 * Input: 3974 * ad aggregate with the invariant 3975 * vthis variable with 'this' 3976 * direct call invariant directly 3977 * Returns: 3978 * void expression that calls the invariant 3979 */ 3980 extern (C++) Expression addInvariant(Loc loc, Scope* sc, AggregateDeclaration ad, VarDeclaration vthis, bool direct) 3981 { 3982 Expression e = null; 3983 if (direct) 3984 { 3985 // Call invariant directly only if it exists 3986 FuncDeclaration inv = ad.inv; 3987 ClassDeclaration cd = ad.isClassDeclaration(); 3988 3989 while (!inv && cd) 3990 { 3991 cd = cd.baseClass; 3992 if (!cd) 3993 break; 3994 inv = cd.inv; 3995 } 3996 if (inv) 3997 { 3998 version (all) 3999 { 4000 // Workaround for bugzilla 13394: For the correct mangling, 4001 // run attribute inference on inv if needed. 4002 inv.functionSemantic(); 4003 } 4004 4005 //e = new DsymbolExp(Loc(), inv); 4006 //e = new CallExp(Loc(), e); 4007 //e = e->semantic(sc2); 4008 4009 /* Bugzilla 13113: Currently virtual invariant calls completely 4010 * bypass attribute enforcement. 4011 * Change the behavior of pre-invariant call by following it. 4012 */ 4013 e = new ThisExp(Loc()); 4014 e.type = vthis.type; 4015 e = new DotVarExp(Loc(), e, inv, false); 4016 e.type = inv.type; 4017 e = new CallExp(Loc(), e); 4018 e.type = Type.tvoid; 4019 } 4020 } 4021 else 4022 { 4023 version (all) 4024 { 4025 // Workaround for bugzilla 13394: For the correct mangling, 4026 // run attribute inference on inv if needed. 4027 if (ad.isStructDeclaration() && ad.inv) 4028 ad.inv.functionSemantic(); 4029 } 4030 // Call invariant virtually 4031 Expression v = new ThisExp(Loc()); 4032 v.type = vthis.type; 4033 if (ad.isStructDeclaration()) 4034 v = v.addressOf(); 4035 e = new StringExp(Loc(), cast(char*)"null this"); 4036 e = new AssertExp(loc, v, e); 4037 e = e.semantic(sc); 4038 } 4039 return e; 4040 } 4041 4042 /*************************************************** 4043 * Visit each overloaded function/template in turn, and call dg(s) on it. 4044 * Exit when no more, or dg(s) returns nonzero. 4045 * Returns: 4046 * ==0 continue 4047 * !=0 done 4048 */ 4049 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg) 4050 { 4051 Dsymbol next; 4052 for (Dsymbol d = fstart; d; d = next) 4053 { 4054 if (auto od = d.isOverDeclaration()) 4055 { 4056 if (od.hasOverloads) 4057 { 4058 if (int r = overloadApply(od.aliassym, dg)) 4059 return r; 4060 } 4061 else 4062 { 4063 if (int r = dg(od.aliassym)) 4064 return r; 4065 } 4066 next = od.overnext; 4067 } 4068 else if (auto fa = d.isFuncAliasDeclaration()) 4069 { 4070 if (fa.hasOverloads) 4071 { 4072 if (int r = overloadApply(fa.funcalias, dg)) 4073 return r; 4074 } 4075 else if (auto fd = fa.toAliasFunc()) 4076 { 4077 if (int r = dg(fd)) 4078 return r; 4079 } 4080 else 4081 { 4082 d.error("is aliased to a function"); 4083 break; 4084 } 4085 next = fa.overnext; 4086 } 4087 else if (auto ad = d.isAliasDeclaration()) 4088 { 4089 next = ad.toAlias(); 4090 if (next == ad) 4091 break; 4092 if (next == fstart) 4093 break; 4094 } 4095 else if (auto td = d.isTemplateDeclaration()) 4096 { 4097 if (int r = dg(td)) 4098 return r; 4099 next = td.overnext; 4100 } 4101 else if (auto fd = d.isFuncDeclaration()) 4102 { 4103 if (int r = dg(fd)) 4104 return r; 4105 next = fd.overnext; 4106 } 4107 else 4108 { 4109 d.error("is aliased to a function"); 4110 break; 4111 // BUG: should print error message? 4112 } 4113 } 4114 return 0; 4115 } 4116 4117 extern (C++) int overloadApply(Dsymbol fstart, void* param, int function(void*, Dsymbol) fp) 4118 { 4119 return overloadApply(fstart, s => (*fp)(param, s)); 4120 } 4121 4122 extern (C++) static void MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod) 4123 { 4124 bool bothMutable = ((lhsMod & rhsMod) == 0); 4125 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0; 4126 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared); 4127 4128 if (lhsMod & MODshared) 4129 buf.writestring("shared "); 4130 else if (sharedMismatch && !(lhsMod & MODimmutable)) 4131 buf.writestring("non-shared "); 4132 4133 if (bothMutable && sharedMismatchOnly) 4134 { 4135 } 4136 else if (lhsMod & MODimmutable) 4137 buf.writestring("immutable "); 4138 else if (lhsMod & MODconst) 4139 buf.writestring("const "); 4140 else if (lhsMod & MODwild) 4141 buf.writestring("inout "); 4142 else 4143 buf.writestring("mutable "); 4144 } 4145 4146 /******************************************* 4147 * Given a symbol that could be either a FuncDeclaration or 4148 * a function template, resolve it to a function symbol. 4149 * loc instantiation location 4150 * sc instantiation scope 4151 * tiargs initial list of template arguments 4152 * tthis if !NULL, the 'this' pointer argument 4153 * fargs arguments to function 4154 * flags 1: do not issue error message on no match, just return NULL 4155 * 2: overloadResolve only 4156 */ 4157 extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, 4158 Objects* tiargs, Type tthis, Expressions* fargs, int flags = 0) 4159 { 4160 if (!s) 4161 return null; // no match 4162 4163 version (none) 4164 { 4165 printf("resolveFuncCall('%s')\n", s.toChars()); 4166 if (fargs) 4167 { 4168 for (size_t i = 0; i < fargs.dim; i++) 4169 { 4170 Expression arg = (*fargs)[i]; 4171 assert(arg.type); 4172 printf("\t%s: ", arg.toChars()); 4173 arg.type.print(); 4174 } 4175 } 4176 } 4177 4178 if (tiargs && arrayObjectIsError(tiargs) || 4179 fargs && arrayObjectIsError(cast(Objects*)fargs)) 4180 { 4181 return null; 4182 } 4183 4184 Match m; 4185 m.last = MATCHnomatch; 4186 4187 functionResolve(&m, s, loc, sc, tiargs, tthis, fargs); 4188 4189 if (m.last > MATCHnomatch && m.lastf) 4190 { 4191 if (m.count == 1) // exactly one match 4192 { 4193 if (!(flags & 1)) 4194 m.lastf.functionSemantic(); 4195 return m.lastf; 4196 } 4197 if ((flags & 2) && !tthis && m.lastf.needThis()) 4198 { 4199 return m.lastf; 4200 } 4201 } 4202 4203 /* Failed to find a best match. 4204 * Do nothing or print error. 4205 */ 4206 if (m.last <= MATCHnomatch) 4207 { 4208 // error was caused on matched function 4209 if (m.count == 1) 4210 return m.lastf; 4211 4212 // if do not print error messages 4213 if (flags & 1) 4214 return null; // no match 4215 } 4216 4217 auto fd = s.isFuncDeclaration(); 4218 auto od = s.isOverDeclaration(); 4219 auto td = s.isTemplateDeclaration(); 4220 if (td && td.funcroot) 4221 s = fd = td.funcroot; 4222 4223 OutBuffer tiargsBuf; 4224 arrayObjectsToBuffer(&tiargsBuf, tiargs); 4225 4226 OutBuffer fargsBuf; 4227 fargsBuf.writeByte('('); 4228 argExpTypesToCBuffer(&fargsBuf, fargs); 4229 fargsBuf.writeByte(')'); 4230 if (tthis) 4231 tthis.modToBuffer(&fargsBuf); 4232 4233 // max num of overloads to print (-v overrides this). 4234 enum int numOverloadsDisplay = 5; 4235 4236 if (!m.lastf && !(flags & 1)) // no match 4237 { 4238 if (td && !fd) // all of overloads are templates 4239 { 4240 .error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:", 4241 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), 4242 tiargsBuf.peekString(), fargsBuf.peekString()); 4243 4244 // Display candidate templates (even if there are no multiple overloads) 4245 int numToDisplay = numOverloadsDisplay; 4246 overloadApply(td, (Dsymbol s) 4247 { 4248 auto td = s.isTemplateDeclaration(); 4249 if (!td) 4250 return 0; 4251 .errorSupplemental(td.loc, "%s", td.toPrettyChars()); 4252 if (global.params.verbose || --numToDisplay != 0 || !td.overnext) 4253 return 0; 4254 4255 // Too many overloads to sensibly display. 4256 // Just show count of remaining overloads. 4257 int num = 0; 4258 overloadApply(td.overnext, (s) { ++num; return 0; }); 4259 if (num > 0) 4260 .errorSupplemental(loc, "... (%d more, -v to show) ...", num); 4261 return 1; // stop iterating 4262 }); 4263 } 4264 else if (od) 4265 { 4266 .error(loc, "none of the overloads of '%s' are callable using argument types !(%s)%s", 4267 od.ident.toChars(), tiargsBuf.peekString(), fargsBuf.peekString()); 4268 } 4269 else 4270 { 4271 assert(fd); 4272 4273 bool hasOverloads = fd.overnext !is null; 4274 auto tf = cast(TypeFunction)fd.type; 4275 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch 4276 { 4277 OutBuffer thisBuf, funcBuf; 4278 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 4279 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 4280 if (hasOverloads) 4281 { 4282 .error(loc, "none of the overloads of '%s' are callable using a %sobject, candidates are:", 4283 fd.ident.toChars(), thisBuf.peekString()); 4284 } 4285 else 4286 { 4287 .error(loc, "%smethod %s is not callable using a %sobject", 4288 funcBuf.peekString(), fd.toPrettyChars(), 4289 thisBuf.peekString()); 4290 } 4291 } 4292 else 4293 { 4294 //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco); 4295 if (hasOverloads) 4296 { 4297 .error(loc, "none of the overloads of '%s' are callable using argument types %s, candidates are:", 4298 fd.ident.toChars(), fargsBuf.peekString()); 4299 } 4300 else 4301 { 4302 fd.error(loc, "%s%s is not callable using argument types %s", 4303 parametersTypeToChars(tf.parameters, tf.varargs), 4304 tf.modToChars(), fargsBuf.peekString()); 4305 } 4306 } 4307 4308 // Display candidate functions 4309 int numToDisplay = numOverloadsDisplay; 4310 overloadApply(hasOverloads ? fd : null, (Dsymbol s) 4311 { 4312 auto fd = s.isFuncDeclaration(); 4313 if (!fd || fd.errors || fd.type.ty == Terror) 4314 return 0; 4315 auto tf = cast(TypeFunction)fd.type; 4316 .errorSupplemental(fd.loc, "%s%s", fd.toPrettyChars(), 4317 parametersTypeToChars(tf.parameters, tf.varargs)); 4318 if (global.params.verbose || --numToDisplay != 0 || !fd.overnext) 4319 return 0; 4320 4321 // Too many overloads to sensibly display. 4322 int num = 0; 4323 overloadApply(fd.overnext, (s){ num += !!s.isFuncDeclaration(); return 0; }); 4324 if (num > 0) 4325 .errorSupplemental(loc, "... (%d more, -v to show) ...", num); 4326 return 1; // stop iterating 4327 }); 4328 } 4329 } 4330 else if (m.nextf) 4331 { 4332 TypeFunction tf1 = cast(TypeFunction)m.lastf.type; 4333 TypeFunction tf2 = cast(TypeFunction)m.nextf.type; 4334 const(char)* lastprms = parametersTypeToChars(tf1.parameters, tf1.varargs); 4335 const(char)* nextprms = parametersTypeToChars(tf2.parameters, tf2.varargs); 4336 .error(loc, "%s.%s called with argument types %s matches both:\n%s: %s%s\nand:\n%s: %s%s", 4337 s.parent.toPrettyChars(), s.ident.toChars(), 4338 fargsBuf.peekString(), 4339 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, 4340 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms); 4341 } 4342 return null; 4343 } 4344 4345 /************************************** 4346 * Returns an indirect type one step from t. 4347 */ 4348 extern (C++) Type getIndirection(Type t) 4349 { 4350 t = t.baseElemOf(); 4351 if (t.ty == Tarray || t.ty == Tpointer) 4352 return t.nextOf().toBasetype(); 4353 if (t.ty == Taarray || t.ty == Tclass) 4354 return t; 4355 if (t.ty == Tstruct) 4356 return t.hasPointers() ? t : null; // TODO 4357 4358 // should consider TypeDelegate? 4359 return null; 4360 } 4361 4362 /************************************** 4363 * Returns true if memory reachable through a reference B to a value of type tb, 4364 * which has been constructed with a reference A to a value of type ta 4365 * available, can alias memory reachable from A based on the types involved 4366 * (either directly or via any number of indirections). 4367 * 4368 * Note that this relation is not symmetric in the two arguments. For example, 4369 * a const(int) reference can point to a pre-existing int, but not the other 4370 * way round. 4371 */ 4372 extern (C++) bool traverseIndirections(Type ta, Type tb, void* p = null, bool reversePass = false) 4373 { 4374 Type source = ta; 4375 Type target = tb; 4376 if (reversePass) 4377 { 4378 source = tb; 4379 target = ta; 4380 } 4381 4382 if (source.constConv(target)) 4383 return true; 4384 else if (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)) 4385 return true; 4386 4387 // No direct match, so try breaking up one of the types (starting with tb). 4388 Type tbb = tb.toBasetype().baseElemOf(); 4389 if (tbb != tb) 4390 return traverseIndirections(ta, tbb, p, reversePass); 4391 4392 // context date to detect circular look up 4393 struct Ctxt 4394 { 4395 Ctxt* prev; 4396 Type type; 4397 } 4398 4399 Ctxt* ctxt = cast(Ctxt*)p; 4400 if (tb.ty == Tclass || tb.ty == Tstruct) 4401 { 4402 for (Ctxt* c = ctxt; c; c = c.prev) 4403 if (tb == c.type) 4404 return false; 4405 Ctxt c; 4406 c.prev = ctxt; 4407 c.type = tb; 4408 4409 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); 4410 for (size_t i = 0; i < sym.fields.dim; i++) 4411 { 4412 VarDeclaration v = sym.fields[i]; 4413 Type tprmi = v.type.addMod(tb.mod); 4414 //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars()); 4415 if (traverseIndirections(ta, tprmi, &c, reversePass)) 4416 return true; 4417 } 4418 } 4419 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) 4420 { 4421 Type tind = tb.nextOf(); 4422 if (traverseIndirections(ta, tind, ctxt, reversePass)) 4423 return true; 4424 } 4425 else if (tb.hasPointers()) 4426 { 4427 // FIXME: function pointer/delegate types should be considered. 4428 return true; 4429 } 4430 4431 // Still no match, so try breaking up ta if we have note done so yet. 4432 if (!reversePass) 4433 return traverseIndirections(tb, ta, ctxt, true); 4434 4435 return false; 4436 } 4437 4438 /* For all functions between outerFunc and f, mark them as needing 4439 * a closure. 4440 */ 4441 extern (C++) void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc) 4442 { 4443 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.parent) 4444 { 4445 FuncDeclaration fy = sx.isFuncDeclaration(); 4446 if (fy && fy.closureVars.dim) 4447 { 4448 /* fy needs a closure if it has closureVars[], 4449 * because the frame pointer in the closure will be accessed. 4450 */ 4451 fy.requiresClosure = true; 4452 } 4453 } 4454 } 4455 4456 /* Given a nested function f inside a function outerFunc, check 4457 * if any sibling callers of f have escaped. If so, mark 4458 * all the enclosing functions as needing closures. 4459 * Return true if any closures were detected. 4460 * This is recursive: we need to check the callers of our siblings. 4461 * Note that nested functions can only call lexically earlier nested 4462 * functions, so loops are impossible. 4463 */ 4464 extern (C++) bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null) 4465 { 4466 struct PrevSibling 4467 { 4468 PrevSibling* p; 4469 FuncDeclaration f; 4470 } 4471 4472 PrevSibling ps; 4473 ps.p = cast(PrevSibling*)p; 4474 ps.f = f; 4475 4476 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars()); 4477 bool bAnyClosures = false; 4478 for (size_t i = 0; i < f.siblingCallers.dim; ++i) 4479 { 4480 FuncDeclaration g = f.siblingCallers[i]; 4481 if (g.isThis() || g.tookAddressOf) 4482 { 4483 markAsNeedingClosure(g, outerFunc); 4484 bAnyClosures = true; 4485 } 4486 4487 PrevSibling* prev = cast(PrevSibling*)p; 4488 while (1) 4489 { 4490 if (!prev) 4491 { 4492 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps); 4493 break; 4494 } 4495 if (prev.f == g) 4496 break; 4497 prev = prev.p; 4498 } 4499 } 4500 //printf("\t%d\n", bAnyClosures); 4501 return bAnyClosures; 4502 } 4503 4504 /*********************************************************** 4505 * Used as a way to import a set of functions from another scope into this one. 4506 */ 4507 extern (C++) final class FuncAliasDeclaration : FuncDeclaration 4508 { 4509 FuncDeclaration funcalias; 4510 bool hasOverloads; 4511 4512 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true) 4513 { 4514 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type); 4515 assert(funcalias != this); 4516 this.funcalias = funcalias; 4517 4518 this.hasOverloads = hasOverloads; 4519 if (hasOverloads) 4520 { 4521 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration()) 4522 this.hasOverloads = fad.hasOverloads; 4523 } 4524 else 4525 { 4526 // for internal use 4527 assert(!funcalias.isFuncAliasDeclaration()); 4528 this.hasOverloads = false; 4529 } 4530 userAttribDecl = funcalias.userAttribDecl; 4531 } 4532 4533 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout 4534 { 4535 return this; 4536 } 4537 4538 override const(char)* kind() const 4539 { 4540 return "function alias"; 4541 } 4542 4543 override FuncDeclaration toAliasFunc() 4544 { 4545 return funcalias.toAliasFunc(); 4546 } 4547 4548 override void accept(Visitor v) 4549 { 4550 v.visit(this); 4551 } 4552 } 4553 4554 /*********************************************************** 4555 */ 4556 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration 4557 { 4558 TOK tok; // TOKfunction or TOKdelegate 4559 Type treq; // target of return type inference 4560 4561 // backend 4562 bool deferToObj; 4563 4564 extern (D) this(Loc loc, Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) 4565 { 4566 super(loc, endloc, null, STCundefined, type); 4567 this.ident = id ? id : Id.empty; 4568 this.tok = tok; 4569 this.fes = fes; 4570 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); 4571 } 4572 4573 override Dsymbol syntaxCopy(Dsymbol s) 4574 { 4575 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); 4576 assert(!s); 4577 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); 4578 f.treq = treq; // don't need to copy 4579 return FuncDeclaration.syntaxCopy(f); 4580 } 4581 4582 override bool isNested() 4583 { 4584 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); 4585 return (tok != TOKfunction) && !isThis(); 4586 } 4587 4588 override AggregateDeclaration isThis() 4589 { 4590 return tok == TOKdelegate ? super.isThis() : null; 4591 } 4592 4593 override bool isVirtual() 4594 { 4595 return false; 4596 } 4597 4598 override bool addPreInvariant() 4599 { 4600 return false; 4601 } 4602 4603 override bool addPostInvariant() 4604 { 4605 return false; 4606 } 4607 4608 /******************************* 4609 * Modify all expression type of return statements to tret. 4610 * 4611 * On function literals, return type may be modified based on the context type 4612 * after its semantic3 is done, in FuncExp::implicitCastTo. 4613 * 4614 * A function() dg = (){ return new B(); } // OK if is(B : A) == true 4615 * 4616 * If B to A conversion is convariant that requires offseet adjusting, 4617 * all return statements should be adjusted to return expressions typed A. 4618 */ 4619 void modifyReturns(Scope* sc, Type tret) 4620 { 4621 extern (C++) final class RetWalker : StatementRewriteWalker 4622 { 4623 alias visit = super.visit; 4624 public: 4625 Scope* sc; 4626 Type tret; 4627 FuncLiteralDeclaration fld; 4628 4629 override void visit(ReturnStatement s) 4630 { 4631 Expression exp = s.exp; 4632 if (exp && !exp.type.equals(tret)) 4633 { 4634 s.exp = exp.castTo(sc, tret); 4635 } 4636 } 4637 } 4638 4639 if (semanticRun < PASSsemantic3done) 4640 return; 4641 4642 if (fes) 4643 return; 4644 4645 scope RetWalker w = new RetWalker(); 4646 w.sc = sc; 4647 w.tret = tret; 4648 w.fld = this; 4649 fbody.accept(w); 4650 4651 // Also update the inferred function type to match the new return type. 4652 // This is required so the code generator does not try to cast the 4653 // modified returns back to the original type. 4654 if (inferRetType && type.nextOf() != tret) 4655 (cast(TypeFunction)type).next = tret; 4656 } 4657 4658 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout 4659 { 4660 return this; 4661 } 4662 4663 override const(char)* kind() const 4664 { 4665 // GCC requires the (char*) casts 4666 return (tok != TOKfunction) ? cast(char*)"delegate" : cast(char*)"function"; 4667 } 4668 4669 override const(char)* toPrettyChars(bool QualifyTypes = false) 4670 { 4671 if (parent) 4672 { 4673 TemplateInstance ti = parent.isTemplateInstance(); 4674 if (ti) 4675 return ti.tempdecl.toPrettyChars(QualifyTypes); 4676 } 4677 return Dsymbol.toPrettyChars(QualifyTypes); 4678 } 4679 4680 override void accept(Visitor v) 4681 { 4682 v.visit(this); 4683 } 4684 } 4685 4686 /*********************************************************** 4687 */ 4688 extern (C++) final class CtorDeclaration : FuncDeclaration 4689 { 4690 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Type type) 4691 { 4692 super(loc, endloc, Id.ctor, stc, type); 4693 //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); 4694 } 4695 4696 override Dsymbol syntaxCopy(Dsymbol s) 4697 { 4698 assert(!s); 4699 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy()); 4700 return FuncDeclaration.syntaxCopy(f); 4701 } 4702 4703 override void semantic(Scope* sc) 4704 { 4705 //printf("CtorDeclaration::semantic() %s\n", toChars()); 4706 if (semanticRun >= PASSsemanticdone) 4707 return; 4708 if (_scope) 4709 { 4710 sc = _scope; 4711 _scope = null; 4712 } 4713 4714 parent = sc.parent; 4715 Dsymbol p = toParent2(); 4716 AggregateDeclaration ad = p.isAggregateDeclaration(); 4717 if (!ad) 4718 { 4719 .error(loc, "constructor can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 4720 type = Type.terror; 4721 errors = true; 4722 return; 4723 } 4724 4725 sc = sc.push(); 4726 sc.stc &= ~STCstatic; // not a static constructor 4727 sc.flags |= SCOPEctor; 4728 4729 FuncDeclaration.semantic(sc); 4730 4731 sc.pop(); 4732 4733 if (errors) 4734 return; 4735 4736 TypeFunction tf = cast(TypeFunction)type; 4737 assert(tf && tf.ty == Tfunction); 4738 4739 /* See if it's the default constructor 4740 * But, template constructor should not become a default constructor. 4741 */ 4742 if (ad && (!parent.isTemplateInstance() || parent.isTemplateMixin())) 4743 { 4744 immutable dim = Parameter.dim(tf.parameters); 4745 4746 if (auto sd = ad.isStructDeclaration()) 4747 { 4748 if (dim == 0 && tf.varargs == 0) // empty default ctor w/o any varargs 4749 { 4750 if (fbody || !(storage_class & STCdisable)) 4751 { 4752 error("default constructor for structs only allowed " ~ 4753 "with @disable, no body, and no parameters"); 4754 storage_class |= STCdisable; 4755 fbody = null; 4756 } 4757 sd.noDefaultCtor = true; 4758 } 4759 else if (dim == 0 && tf.varargs) // allow varargs only ctor 4760 { 4761 } 4762 else if (dim && Parameter.getNth(tf.parameters, 0).defaultArg) 4763 { 4764 // if the first parameter has a default argument, then the rest does as well 4765 if (storage_class & STCdisable) 4766 { 4767 deprecation("@disable'd constructor cannot have default "~ 4768 "arguments for all parameters."); 4769 deprecationSupplemental(loc, "Use @disable this(); if you want to disable default initialization."); 4770 } 4771 else 4772 deprecation("all parameters have default arguments, "~ 4773 "but structs cannot have default constructors."); 4774 } 4775 } 4776 else if (dim == 0 && tf.varargs == 0) 4777 { 4778 ad.defaultCtor = this; 4779 } 4780 } 4781 } 4782 4783 override const(char)* kind() const 4784 { 4785 return "constructor"; 4786 } 4787 4788 override const(char)* toChars() const 4789 { 4790 return "this"; 4791 } 4792 4793 override bool isVirtual() 4794 { 4795 return false; 4796 } 4797 4798 override bool addPreInvariant() 4799 { 4800 return false; 4801 } 4802 4803 override bool addPostInvariant() 4804 { 4805 return (isThis() && vthis && global.params.useInvariants); 4806 } 4807 4808 override inout(CtorDeclaration) isCtorDeclaration() inout 4809 { 4810 return this; 4811 } 4812 4813 override void accept(Visitor v) 4814 { 4815 v.visit(this); 4816 } 4817 } 4818 4819 /*********************************************************** 4820 */ 4821 extern (C++) final class PostBlitDeclaration : FuncDeclaration 4822 { 4823 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Identifier id) 4824 { 4825 super(loc, endloc, id, stc, null); 4826 } 4827 4828 override Dsymbol syntaxCopy(Dsymbol s) 4829 { 4830 assert(!s); 4831 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident); 4832 return FuncDeclaration.syntaxCopy(dd); 4833 } 4834 4835 override void semantic(Scope* sc) 4836 { 4837 //printf("PostBlitDeclaration::semantic() %s\n", toChars()); 4838 //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); 4839 //printf("stc = x%llx\n", sc->stc); 4840 if (semanticRun >= PASSsemanticdone) 4841 return; 4842 if (_scope) 4843 { 4844 sc = _scope; 4845 _scope = null; 4846 } 4847 4848 parent = sc.parent; 4849 Dsymbol p = toParent2(); 4850 StructDeclaration ad = p.isStructDeclaration(); 4851 if (!ad) 4852 { 4853 .error(loc, "postblit can only be a member of struct/union, not %s %s", p.kind(), p.toChars()); 4854 type = Type.terror; 4855 errors = true; 4856 return; 4857 } 4858 if (ident == Id.postblit && semanticRun < PASSsemantic) 4859 ad.postblits.push(this); 4860 if (!type) 4861 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 4862 4863 sc = sc.push(); 4864 sc.stc &= ~STCstatic; // not static 4865 sc.linkage = LINKd; 4866 4867 FuncDeclaration.semantic(sc); 4868 4869 sc.pop(); 4870 } 4871 4872 override bool isVirtual() 4873 { 4874 return false; 4875 } 4876 4877 override bool addPreInvariant() 4878 { 4879 return false; 4880 } 4881 4882 override bool addPostInvariant() 4883 { 4884 return (isThis() && vthis && global.params.useInvariants); 4885 } 4886 4887 override bool overloadInsert(Dsymbol s) 4888 { 4889 return false; // cannot overload postblits 4890 } 4891 4892 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout 4893 { 4894 return this; 4895 } 4896 4897 override void accept(Visitor v) 4898 { 4899 v.visit(this); 4900 } 4901 } 4902 4903 /*********************************************************** 4904 */ 4905 extern (C++) final class DtorDeclaration : FuncDeclaration 4906 { 4907 extern (D) this(Loc loc, Loc endloc) 4908 { 4909 super(loc, endloc, Id.dtor, STCundefined, null); 4910 } 4911 4912 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Identifier id) 4913 { 4914 super(loc, endloc, id, stc, null); 4915 } 4916 4917 override Dsymbol syntaxCopy(Dsymbol s) 4918 { 4919 assert(!s); 4920 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident); 4921 return FuncDeclaration.syntaxCopy(dd); 4922 } 4923 4924 override void semantic(Scope* sc) 4925 { 4926 //printf("DtorDeclaration::semantic() %s\n", toChars()); 4927 //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); 4928 if (semanticRun >= PASSsemanticdone) 4929 return; 4930 if (_scope) 4931 { 4932 sc = _scope; 4933 _scope = null; 4934 } 4935 4936 parent = sc.parent; 4937 Dsymbol p = toParent2(); 4938 AggregateDeclaration ad = p.isAggregateDeclaration(); 4939 if (!ad) 4940 { 4941 .error(loc, "destructor can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 4942 type = Type.terror; 4943 errors = true; 4944 return; 4945 } 4946 if (ident == Id.dtor && semanticRun < PASSsemantic) 4947 ad.dtors.push(this); 4948 if (!type) 4949 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 4950 4951 sc = sc.push(); 4952 sc.stc &= ~STCstatic; // not a static destructor 4953 if (sc.linkage != LINKcpp) 4954 sc.linkage = LINKd; 4955 4956 FuncDeclaration.semantic(sc); 4957 4958 sc.pop(); 4959 } 4960 4961 override const(char)* kind() const 4962 { 4963 return "destructor"; 4964 } 4965 4966 override const(char)* toChars() const 4967 { 4968 return "~this"; 4969 } 4970 4971 override bool isVirtual() 4972 { 4973 // false so that dtor's don't get put into the vtbl[] 4974 return false; 4975 } 4976 4977 override bool addPreInvariant() 4978 { 4979 return (isThis() && vthis && global.params.useInvariants); 4980 } 4981 4982 override bool addPostInvariant() 4983 { 4984 return false; 4985 } 4986 4987 override bool overloadInsert(Dsymbol s) 4988 { 4989 return false; // cannot overload destructors 4990 } 4991 4992 override inout(DtorDeclaration) isDtorDeclaration() inout 4993 { 4994 return this; 4995 } 4996 4997 override void accept(Visitor v) 4998 { 4999 v.visit(this); 5000 } 5001 } 5002 5003 /*********************************************************** 5004 */ 5005 extern (C++) class StaticCtorDeclaration : FuncDeclaration 5006 { 5007 final extern (D) this(Loc loc, Loc endloc, StorageClass stc) 5008 { 5009 super(loc, endloc, Identifier.generateId("_staticCtor"), STCstatic | stc, null); 5010 } 5011 5012 final extern (D) this(Loc loc, Loc endloc, const(char)* name, StorageClass stc) 5013 { 5014 super(loc, endloc, Identifier.generateId(name), STCstatic | stc, null); 5015 } 5016 5017 override Dsymbol syntaxCopy(Dsymbol s) 5018 { 5019 assert(!s); 5020 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class); 5021 return FuncDeclaration.syntaxCopy(scd); 5022 } 5023 5024 override final void semantic(Scope* sc) 5025 { 5026 //printf("StaticCtorDeclaration::semantic()\n"); 5027 if (semanticRun >= PASSsemanticdone) 5028 return; 5029 if (_scope) 5030 { 5031 sc = _scope; 5032 _scope = null; 5033 } 5034 5035 parent = sc.parent; 5036 Dsymbol p = parent.pastMixin(); 5037 if (!p.isScopeDsymbol()) 5038 { 5039 const(char)* s = (isSharedStaticCtorDeclaration() ? "shared " : ""); 5040 .error(loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s", s, p.kind(), p.toChars()); 5041 type = Type.terror; 5042 errors = true; 5043 return; 5044 } 5045 if (!type) 5046 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 5047 5048 /* If the static ctor appears within a template instantiation, 5049 * it could get called multiple times by the module constructors 5050 * for different modules. Thus, protect it with a gate. 5051 */ 5052 if (isInstantiated() && semanticRun < PASSsemantic) 5053 { 5054 /* Add this prefix to the function: 5055 * static int gate; 5056 * if (++gate != 1) return; 5057 * Note that this is not thread safe; should not have threads 5058 * during static construction. 5059 */ 5060 auto v = new VarDeclaration(Loc(), Type.tint32, Id.gate, null); 5061 v.storage_class = STCtemp | (isSharedStaticCtorDeclaration() ? STCstatic : STCtls); 5062 5063 auto sa = new Statements(); 5064 Statement s = new ExpStatement(Loc(), v); 5065 sa.push(s); 5066 5067 Expression e = new IdentifierExp(Loc(), v.ident); 5068 e = new AddAssignExp(Loc(), e, new IntegerExp(1)); 5069 e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1)); 5070 s = new IfStatement(Loc(), null, e, new ReturnStatement(Loc(), null), null, Loc()); 5071 5072 sa.push(s); 5073 if (fbody) 5074 sa.push(fbody); 5075 5076 fbody = new CompoundStatement(Loc(), sa); 5077 } 5078 5079 FuncDeclaration.semantic(sc); 5080 5081 // We're going to need ModuleInfo 5082 Module m = getModule(); 5083 if (!m) 5084 m = sc._module; 5085 if (m) 5086 { 5087 m.needmoduleinfo = 1; 5088 //printf("module1 %s needs moduleinfo\n", m->toChars()); 5089 } 5090 } 5091 5092 override final AggregateDeclaration isThis() 5093 { 5094 return null; 5095 } 5096 5097 override final bool isVirtual() 5098 { 5099 return false; 5100 } 5101 5102 override final bool addPreInvariant() 5103 { 5104 return false; 5105 } 5106 5107 override final bool addPostInvariant() 5108 { 5109 return false; 5110 } 5111 5112 override final bool hasStaticCtorOrDtor() 5113 { 5114 return true; 5115 } 5116 5117 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout 5118 { 5119 return this; 5120 } 5121 5122 override void accept(Visitor v) 5123 { 5124 v.visit(this); 5125 } 5126 } 5127 5128 /*********************************************************** 5129 */ 5130 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration 5131 { 5132 extern (D) this(Loc loc, Loc endloc, StorageClass stc) 5133 { 5134 super(loc, endloc, "_sharedStaticCtor", stc); 5135 } 5136 5137 override Dsymbol syntaxCopy(Dsymbol s) 5138 { 5139 assert(!s); 5140 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class); 5141 return FuncDeclaration.syntaxCopy(scd); 5142 } 5143 5144 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout 5145 { 5146 return this; 5147 } 5148 5149 override void accept(Visitor v) 5150 { 5151 v.visit(this); 5152 } 5153 } 5154 5155 /*********************************************************** 5156 */ 5157 extern (C++) class StaticDtorDeclaration : FuncDeclaration 5158 { 5159 VarDeclaration vgate; // 'gate' variable 5160 5161 final extern (D) this(Loc loc, Loc endloc, StorageClass stc) 5162 { 5163 super(loc, endloc, Identifier.generateId("_staticDtor"), STCstatic | stc, null); 5164 } 5165 5166 final extern (D) this(Loc loc, Loc endloc, const(char)* name, StorageClass stc) 5167 { 5168 super(loc, endloc, Identifier.generateId(name), STCstatic | stc, null); 5169 } 5170 5171 override Dsymbol syntaxCopy(Dsymbol s) 5172 { 5173 assert(!s); 5174 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class); 5175 return FuncDeclaration.syntaxCopy(sdd); 5176 } 5177 5178 override final void semantic(Scope* sc) 5179 { 5180 if (semanticRun >= PASSsemanticdone) 5181 return; 5182 if (_scope) 5183 { 5184 sc = _scope; 5185 _scope = null; 5186 } 5187 5188 parent = sc.parent; 5189 Dsymbol p = parent.pastMixin(); 5190 if (!p.isScopeDsymbol()) 5191 { 5192 const(char)* s = (isSharedStaticDtorDeclaration() ? "shared " : ""); 5193 .error(loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s", s, p.kind(), p.toChars()); 5194 type = Type.terror; 5195 errors = true; 5196 return; 5197 } 5198 if (!type) 5199 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 5200 5201 /* If the static ctor appears within a template instantiation, 5202 * it could get called multiple times by the module constructors 5203 * for different modules. Thus, protect it with a gate. 5204 */ 5205 if (isInstantiated() && semanticRun < PASSsemantic) 5206 { 5207 /* Add this prefix to the function: 5208 * static int gate; 5209 * if (--gate != 0) return; 5210 * Increment gate during constructor execution. 5211 * Note that this is not thread safe; should not have threads 5212 * during static destruction. 5213 */ 5214 auto v = new VarDeclaration(Loc(), Type.tint32, Id.gate, null); 5215 v.storage_class = STCtemp | (isSharedStaticDtorDeclaration() ? STCstatic : STCtls); 5216 5217 auto sa = new Statements(); 5218 Statement s = new ExpStatement(Loc(), v); 5219 sa.push(s); 5220 5221 Expression e = new IdentifierExp(Loc(), v.ident); 5222 e = new AddAssignExp(Loc(), e, new IntegerExp(-1)); 5223 e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0)); 5224 s = new IfStatement(Loc(), null, e, new ReturnStatement(Loc(), null), null, Loc()); 5225 5226 sa.push(s); 5227 if (fbody) 5228 sa.push(fbody); 5229 5230 fbody = new CompoundStatement(Loc(), sa); 5231 5232 vgate = v; 5233 } 5234 5235 FuncDeclaration.semantic(sc); 5236 5237 // We're going to need ModuleInfo 5238 Module m = getModule(); 5239 if (!m) 5240 m = sc._module; 5241 if (m) 5242 { 5243 m.needmoduleinfo = 1; 5244 //printf("module2 %s needs moduleinfo\n", m->toChars()); 5245 } 5246 } 5247 5248 override final AggregateDeclaration isThis() 5249 { 5250 return null; 5251 } 5252 5253 override final bool isVirtual() 5254 { 5255 return false; 5256 } 5257 5258 override final bool hasStaticCtorOrDtor() 5259 { 5260 return true; 5261 } 5262 5263 override final bool addPreInvariant() 5264 { 5265 return false; 5266 } 5267 5268 override final bool addPostInvariant() 5269 { 5270 return false; 5271 } 5272 5273 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout 5274 { 5275 return this; 5276 } 5277 5278 override void accept(Visitor v) 5279 { 5280 v.visit(this); 5281 } 5282 } 5283 5284 /*********************************************************** 5285 */ 5286 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration 5287 { 5288 extern (D) this(Loc loc, Loc endloc, StorageClass stc) 5289 { 5290 super(loc, endloc, "_sharedStaticDtor", stc); 5291 } 5292 5293 override Dsymbol syntaxCopy(Dsymbol s) 5294 { 5295 assert(!s); 5296 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class); 5297 return FuncDeclaration.syntaxCopy(sdd); 5298 } 5299 5300 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout 5301 { 5302 return this; 5303 } 5304 5305 override void accept(Visitor v) 5306 { 5307 v.visit(this); 5308 } 5309 } 5310 5311 /*********************************************************** 5312 */ 5313 extern (C++) final class InvariantDeclaration : FuncDeclaration 5314 { 5315 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Identifier id, Statement fbody) 5316 { 5317 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); 5318 this.fbody = fbody; 5319 } 5320 5321 override Dsymbol syntaxCopy(Dsymbol s) 5322 { 5323 assert(!s); 5324 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null); 5325 return FuncDeclaration.syntaxCopy(id); 5326 } 5327 5328 override void semantic(Scope* sc) 5329 { 5330 if (semanticRun >= PASSsemanticdone) 5331 return; 5332 if (_scope) 5333 { 5334 sc = _scope; 5335 _scope = null; 5336 } 5337 5338 parent = sc.parent; 5339 Dsymbol p = parent.pastMixin(); 5340 AggregateDeclaration ad = p.isAggregateDeclaration(); 5341 if (!ad) 5342 { 5343 .error(loc, "invariant can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 5344 type = Type.terror; 5345 errors = true; 5346 return; 5347 } 5348 if (ident != Id.classInvariant && 5349 semanticRun < PASSsemantic && 5350 !ad.isUnionDeclaration() // users are on their own with union fields 5351 ) 5352 ad.invs.push(this); 5353 if (!type) 5354 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 5355 5356 sc = sc.push(); 5357 sc.stc &= ~STCstatic; // not a static invariant 5358 sc.stc |= STCconst; // invariant() is always const 5359 sc.flags = (sc.flags & ~SCOPEcontract) | SCOPEinvariant; 5360 sc.linkage = LINKd; 5361 5362 FuncDeclaration.semantic(sc); 5363 5364 sc.pop(); 5365 } 5366 5367 override bool isVirtual() 5368 { 5369 return false; 5370 } 5371 5372 override bool addPreInvariant() 5373 { 5374 return false; 5375 } 5376 5377 override bool addPostInvariant() 5378 { 5379 return false; 5380 } 5381 5382 override inout(InvariantDeclaration) isInvariantDeclaration() inout 5383 { 5384 return this; 5385 } 5386 5387 override void accept(Visitor v) 5388 { 5389 v.visit(this); 5390 } 5391 } 5392 5393 /*********************************************************** 5394 * Generate unique unittest function Id so we can have multiple 5395 * instances per module. 5396 */ 5397 extern (C++) static Identifier unitTestId(Loc loc) 5398 { 5399 OutBuffer buf; 5400 buf.printf("__unittestL%u_", loc.linnum); 5401 return Identifier.generateId(buf.peekString()); 5402 } 5403 5404 /*********************************************************** 5405 */ 5406 extern (C++) final class UnitTestDeclaration : FuncDeclaration 5407 { 5408 char* codedoc; // for documented unittest 5409 5410 // toObjFile() these nested functions after this one 5411 FuncDeclarations deferredNested; 5412 5413 extern (D) this(Loc loc, Loc endloc, StorageClass stc, char* codedoc) 5414 { 5415 super(loc, endloc, unitTestId(loc), stc, null); 5416 this.codedoc = codedoc; 5417 } 5418 5419 override Dsymbol syntaxCopy(Dsymbol s) 5420 { 5421 assert(!s); 5422 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); 5423 return FuncDeclaration.syntaxCopy(utd); 5424 } 5425 5426 override void semantic(Scope* sc) 5427 { 5428 if (semanticRun >= PASSsemanticdone) 5429 return; 5430 if (_scope) 5431 { 5432 sc = _scope; 5433 _scope = null; 5434 } 5435 5436 protection = sc.protection; 5437 5438 parent = sc.parent; 5439 Dsymbol p = parent.pastMixin(); 5440 if (!p.isScopeDsymbol()) 5441 { 5442 .error(loc, "unittest can only be a member of module/aggregate/template, not %s %s", p.kind(), p.toChars()); 5443 type = Type.terror; 5444 errors = true; 5445 return; 5446 } 5447 5448 if (global.params.useUnitTests) 5449 { 5450 if (!type) 5451 type = new TypeFunction(null, Type.tvoid, false, LINKd, storage_class); 5452 Scope* sc2 = sc.push(); 5453 sc2.linkage = LINKd; 5454 FuncDeclaration.semantic(sc2); 5455 sc2.pop(); 5456 } 5457 5458 version (none) 5459 { 5460 // We're going to need ModuleInfo even if the unit tests are not 5461 // compiled in, because other modules may import this module and refer 5462 // to this ModuleInfo. 5463 // (This doesn't make sense to me?) 5464 Module m = getModule(); 5465 if (!m) 5466 m = sc._module; 5467 if (m) 5468 { 5469 //printf("module3 %s needs moduleinfo\n", m->toChars()); 5470 m.needmoduleinfo = 1; 5471 } 5472 } 5473 } 5474 5475 override AggregateDeclaration isThis() 5476 { 5477 return null; 5478 } 5479 5480 override bool isVirtual() 5481 { 5482 return false; 5483 } 5484 5485 override bool addPreInvariant() 5486 { 5487 return false; 5488 } 5489 5490 override bool addPostInvariant() 5491 { 5492 return false; 5493 } 5494 5495 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout 5496 { 5497 return this; 5498 } 5499 5500 override void accept(Visitor v) 5501 { 5502 v.visit(this); 5503 } 5504 } 5505 5506 /*********************************************************** 5507 */ 5508 extern (C++) final class NewDeclaration : FuncDeclaration 5509 { 5510 Parameters* parameters; 5511 int varargs; 5512 5513 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Parameters* fparams, int varargs) 5514 { 5515 super(loc, endloc, Id.classNew, STCstatic | stc, null); 5516 this.parameters = fparams; 5517 this.varargs = varargs; 5518 } 5519 5520 override Dsymbol syntaxCopy(Dsymbol s) 5521 { 5522 assert(!s); 5523 auto f = new NewDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters), varargs); 5524 return FuncDeclaration.syntaxCopy(f); 5525 } 5526 5527 override void semantic(Scope* sc) 5528 { 5529 //printf("NewDeclaration::semantic()\n"); 5530 if (semanticRun >= PASSsemanticdone) 5531 return; 5532 if (_scope) 5533 { 5534 sc = _scope; 5535 _scope = null; 5536 } 5537 5538 parent = sc.parent; 5539 Dsymbol p = parent.pastMixin(); 5540 if (!p.isAggregateDeclaration()) 5541 { 5542 .error(loc, "allocator can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 5543 type = Type.terror; 5544 errors = true; 5545 return; 5546 } 5547 Type tret = Type.tvoid.pointerTo(); 5548 if (!type) 5549 type = new TypeFunction(parameters, tret, varargs, LINKd, storage_class); 5550 5551 type = type.semantic(loc, sc); 5552 assert(type.ty == Tfunction); 5553 5554 // Check that there is at least one argument of type size_t 5555 TypeFunction tf = cast(TypeFunction)type; 5556 if (Parameter.dim(tf.parameters) < 1) 5557 { 5558 error("at least one argument of type size_t expected"); 5559 } 5560 else 5561 { 5562 Parameter fparam = Parameter.getNth(tf.parameters, 0); 5563 if (!fparam.type.equals(Type.tsize_t)) 5564 error("first argument must be type size_t, not %s", fparam.type.toChars()); 5565 } 5566 5567 FuncDeclaration.semantic(sc); 5568 } 5569 5570 override const(char)* kind() const 5571 { 5572 return "allocator"; 5573 } 5574 5575 override bool isVirtual() 5576 { 5577 return false; 5578 } 5579 5580 override bool addPreInvariant() 5581 { 5582 return false; 5583 } 5584 5585 override bool addPostInvariant() 5586 { 5587 return false; 5588 } 5589 5590 override inout(NewDeclaration) isNewDeclaration() inout 5591 { 5592 return this; 5593 } 5594 5595 override void accept(Visitor v) 5596 { 5597 v.visit(this); 5598 } 5599 } 5600 5601 /*********************************************************** 5602 */ 5603 extern (C++) final class DeleteDeclaration : FuncDeclaration 5604 { 5605 Parameters* parameters; 5606 5607 extern (D) this(Loc loc, Loc endloc, StorageClass stc, Parameters* fparams) 5608 { 5609 super(loc, endloc, Id.classDelete, STCstatic | stc, null); 5610 this.parameters = fparams; 5611 } 5612 5613 override Dsymbol syntaxCopy(Dsymbol s) 5614 { 5615 assert(!s); 5616 auto f = new DeleteDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters)); 5617 return FuncDeclaration.syntaxCopy(f); 5618 } 5619 5620 override void semantic(Scope* sc) 5621 { 5622 //printf("DeleteDeclaration::semantic()\n"); 5623 if (semanticRun >= PASSsemanticdone) 5624 return; 5625 if (_scope) 5626 { 5627 sc = _scope; 5628 _scope = null; 5629 } 5630 5631 parent = sc.parent; 5632 Dsymbol p = parent.pastMixin(); 5633 if (!p.isAggregateDeclaration()) 5634 { 5635 .error(loc, "deallocator can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 5636 type = Type.terror; 5637 errors = true; 5638 return; 5639 } 5640 if (!type) 5641 type = new TypeFunction(parameters, Type.tvoid, 0, LINKd, storage_class); 5642 5643 type = type.semantic(loc, sc); 5644 assert(type.ty == Tfunction); 5645 5646 // Check that there is only one argument of type void* 5647 TypeFunction tf = cast(TypeFunction)type; 5648 if (Parameter.dim(tf.parameters) != 1) 5649 { 5650 error("one argument of type void* expected"); 5651 } 5652 else 5653 { 5654 Parameter fparam = Parameter.getNth(tf.parameters, 0); 5655 if (!fparam.type.equals(Type.tvoid.pointerTo())) 5656 error("one argument of type void* expected, not %s", fparam.type.toChars()); 5657 } 5658 5659 FuncDeclaration.semantic(sc); 5660 } 5661 5662 override const(char)* kind() const 5663 { 5664 return "deallocator"; 5665 } 5666 5667 override bool isDelete() 5668 { 5669 return true; 5670 } 5671 5672 override bool isVirtual() 5673 { 5674 return false; 5675 } 5676 5677 override bool addPreInvariant() 5678 { 5679 return false; 5680 } 5681 5682 override bool addPostInvariant() 5683 { 5684 return false; 5685 } 5686 5687 override inout(DeleteDeclaration) isDeleteDeclaration() inout 5688 { 5689 return this; 5690 } 5691 5692 override void accept(Visitor v) 5693 { 5694 v.visit(this); 5695 } 5696 }