1 /** 2 * Defines a function declaration. 3 * 4 * Includes: 5 * - function/delegate literals 6 * - function aliases 7 * - (static/shared) constructors/destructors/post-blits 8 * - `invariant` 9 * - `unittest` 10 * 11 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 12 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 13 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) 15 * Documentation: https://dlang.org/phobos/dmd_func.html 16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d 17 */ 18 19 module dmd.func; 20 21 import core.stdc.stdio; 22 import core.stdc.string; 23 import dmd.aggregate; 24 import dmd.arraytypes; 25 import dmd.blockexit; 26 import dmd.gluelayer; 27 import dmd.dclass; 28 import dmd.declaration; 29 import dmd.delegatize; 30 import dmd.dinterpret; 31 import dmd.dmodule; 32 import dmd.dscope; 33 import dmd.dstruct; 34 import dmd.dsymbol; 35 import dmd.dsymbolsem; 36 import dmd.dtemplate; 37 import dmd.errors; 38 import dmd.escape; 39 import dmd.expression; 40 import dmd.globals; 41 import dmd.hdrgen; 42 import dmd.id; 43 import dmd.identifier; 44 import dmd.init; 45 import dmd.mtype; 46 import dmd.objc; 47 import dmd.root.outbuffer; 48 import dmd.root.rootobject; 49 import dmd.root.string; 50 import dmd.root.stringtable; 51 import dmd.semantic2; 52 import dmd.semantic3; 53 import dmd.statement_rewrite_walker; 54 import dmd.statement; 55 import dmd.statementsem; 56 import dmd.tokens; 57 import dmd.visitor; 58 59 /// Inline Status 60 enum ILS : int 61 { 62 uninitialized, /// not computed yet 63 no, /// cannot inline 64 yes, /// can inline 65 } 66 67 enum BUILTIN : ubyte 68 { 69 unknown = 255, /// not known if this is a builtin 70 unimp = 0, /// this is not a builtin 71 gcc, /// this is a GCC builtin 72 llvm, /// this is an LLVM builtin 73 sin, 74 cos, 75 tan, 76 sqrt, 77 fabs, 78 ldexp, 79 log, 80 log2, 81 log10, 82 exp, 83 expm1, 84 exp2, 85 round, 86 floor, 87 ceil, 88 trunc, 89 copysign, 90 pow, 91 fmin, 92 fmax, 93 fma, 94 isnan, 95 isinfinity, 96 isfinite, 97 bsf, 98 bsr, 99 bswap, 100 popcnt, 101 yl2x, 102 yl2xp1, 103 toPrecFloat, 104 toPrecDouble, 105 toPrecReal 106 } 107 108 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. 109 */ 110 extern (C++) final class NrvoWalker : StatementRewriteWalker 111 { 112 alias visit = typeof(super).visit; 113 public: 114 FuncDeclaration fd; 115 Scope* sc; 116 117 override void visit(ReturnStatement s) 118 { 119 // See if all returns are instead to be replaced with a goto returnLabel; 120 if (fd.returnLabel) 121 { 122 /* Rewrite: 123 * return exp; 124 * as: 125 * vresult = exp; goto Lresult; 126 */ 127 auto gs = new GotoStatement(s.loc, Id.returnLabel); 128 gs.label = fd.returnLabel; 129 130 Statement s1 = gs; 131 if (s.exp) 132 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); 133 134 replaceCurrent(s1); 135 } 136 } 137 138 override void visit(TryFinallyStatement s) 139 { 140 DtorExpStatement des; 141 if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && 142 fd.nrvo_var == des.var) 143 { 144 if (!(global.params.useExceptions && ClassDeclaration.throwable)) 145 { 146 /* Don't need to call destructor at all, since it is nrvo 147 */ 148 replaceCurrent(s._body); 149 s._body.accept(this); 150 return; 151 } 152 153 /* Normally local variable dtors are called regardless exceptions. 154 * But for nrvo_var, its dtor should be called only when exception is thrown. 155 * 156 * Rewrite: 157 * try { s.body; } finally { nrvo_var.edtor; } 158 * // equivalent with: 159 * // s.body; scope(exit) nrvo_var.edtor; 160 * as: 161 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; } 162 * // equivalent with: 163 * // s.body; scope(failure) nrvo_var.edtor; 164 */ 165 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var); 166 Identifier id = Identifier.generateId("__o"); 167 168 Statement handler = new PeelStatement(sexception); 169 if (sexception.blockExit(fd, false) & BE.fallthru) 170 { 171 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); 172 ts.internalThrow = true; 173 handler = new CompoundStatement(Loc.initial, handler, ts); 174 } 175 176 auto catches = new Catches(); 177 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); 178 ctch.internalCatch = true; 179 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o' 180 catches.push(ctch); 181 182 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); 183 fd.eh_none = false; 184 replaceCurrent(s2); 185 s2.accept(this); 186 } 187 else 188 StatementRewriteWalker.visit(s); 189 } 190 } 191 192 enum FUNCFLAG : uint 193 { 194 purityInprocess = 1, /// working on determining purity 195 safetyInprocess = 2, /// working on determining safety 196 nothrowInprocess = 4, /// working on determining nothrow 197 nogcInprocess = 8, /// working on determining @nogc 198 returnInprocess = 0x10, /// working on inferring 'return' for parameters 199 inlineScanned = 0x20, /// function has been scanned for inline possibilities 200 inferScope = 0x40, /// infer 'scope' for parameters 201 hasCatches = 0x80, /// function has try-catch statements 202 compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it 203 printf = 0x200, /// is a printf-like function 204 scanf = 0x400, /// is a scanf-like function 205 } 206 207 /*********************************************************** 208 * Tuple of result identifier (possibly null) and statement. 209 * This is used to store out contracts: out(id){ ensure } 210 */ 211 extern (C++) struct Ensure 212 { 213 Identifier id; 214 Statement ensure; 215 216 Ensure syntaxCopy() 217 { 218 return Ensure(id, ensure.syntaxCopy()); 219 } 220 221 /***************************************** 222 * Do syntax copy of an array of Ensure's. 223 */ 224 static Ensures* arraySyntaxCopy(Ensures* a) 225 { 226 Ensures* b = null; 227 if (a) 228 { 229 b = a.copy(); 230 foreach (i, e; *a) 231 { 232 (*b)[i] = e.syntaxCopy(); 233 } 234 } 235 return b; 236 } 237 238 } 239 240 /*********************************************************** 241 */ 242 extern (C++) class FuncDeclaration : Declaration 243 { 244 Statements* frequires; /// in contracts 245 Ensures* fensures; /// out contracts 246 Statement frequire; /// lowered in contract 247 Statement fensure; /// lowered out contract 248 Statement fbody; /// function body 249 250 FuncDeclarations foverrides; /// functions this function overrides 251 FuncDeclaration fdrequire; /// function that does the in contract 252 FuncDeclaration fdensure; /// function that does the out contract 253 254 Expressions* fdrequireParams; /// argument list for __require 255 Expressions* fdensureParams; /// argument list for __ensure 256 257 const(char)* mangleString; /// mangled symbol created from mangleExact() 258 259 VarDeclaration vresult; /// result variable for out contracts 260 LabelDsymbol returnLabel; /// where the return goes 261 262 // used to prevent symbols in different 263 // scopes from having the same name 264 DsymbolTable localsymtab; 265 VarDeclaration vthis; /// 'this' parameter (member and nested) 266 bool isThis2; /// has a dual-context 'this' parameter 267 VarDeclaration v_arguments; /// '_arguments' parameter 268 269 VarDeclaration v_argptr; /// '_argptr' variable 270 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters 271 DsymbolTable labtab; /// statement label symbol table 272 Dsymbol overnext; /// next in overload list 273 FuncDeclaration overnext0; /// next in overload list (only used during IFTI) 274 Loc endloc; /// location of closing curly bracket 275 int vtblIndex = -1; /// for member functions, index into vtbl[] 276 bool naked; /// true if naked 277 bool generated; /// true if function was generated by the compiler rather than 278 /// supplied by the user 279 bool hasAlwaysInlines; /// contains references to functions that must be inlined 280 ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2)) 281 /// not set before the glue layer 282 283 ILS inlineStatusStmt = ILS.uninitialized; 284 ILS inlineStatusExp = ILS.uninitialized; 285 PINLINE inlining = PINLINE.default_; 286 287 int inlineNest; /// !=0 if nested inline 288 bool eh_none; /// true if no exception unwinding is needed 289 290 bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr 291 ForeachStatement fes; /// if foreach body, this is the foreach 292 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[] 293 bool introducing; /// true if 'introducing' function 294 /** if !=NULL, then this is the type 295 of the 'introducing' function 296 this one is overriding 297 */ 298 Type tintro; 299 300 bool inferRetType; /// true if return type is to be inferred 301 StorageClass storage_class2; /// storage class for template onemember's 302 303 // Things that should really go into Scope 304 305 /// 1 if there's a return exp; statement 306 /// 2 if there's a throw statement 307 /// 4 if there's an assert(0) 308 /// 8 if there's inline asm 309 /// 16 if there are multiple return statements 310 int hasReturnExp; 311 312 // Support for NRVO (named return value optimization) 313 bool nrvo_can = true; /// true means we can do NRVO 314 VarDeclaration nrvo_var; /// variable to replace with shidden 315 Symbol* shidden; /// hidden pointer passed to function 316 317 ReturnStatements* returns; 318 319 GotoStatements* gotos; /// Gotos with forward references 320 321 /// set if this is a known, builtin function we can evaluate at compile time 322 BUILTIN builtin = BUILTIN.unknown; 323 324 /// set if someone took the address of this function 325 int tookAddressOf; 326 327 bool requiresClosure; // this function needs a closure 328 329 /** local variables in this function which are referenced by nested functions 330 * (They'll get put into the "closure" for this function.) 331 */ 332 VarDeclarations closureVars; 333 334 /** Outer variables which are referenced by this nested function 335 * (the inverse of closureVars) 336 */ 337 VarDeclarations outerVars; 338 339 /// Sibling nested functions which called this one 340 FuncDeclarations siblingCallers; 341 342 FuncDeclarations *inlinedNestedCallees; 343 344 uint flags; /// FUNCFLAG.xxxxx 345 346 /** 347 * Data for a function declaration that is needed for the Objective-C 348 * integration. 349 */ 350 ObjcFuncDeclaration objc; 351 352 extern (D) bool delegate(FuncDeclaration func, Scope* scope_, bool delegate(Scope*) defaultCanInferAttributes) canInferAttributesOverride; 353 354 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type) 355 { 356 super(loc, ident); 357 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); 358 //printf("storage_class = x%x\n", storage_class); 359 this.storage_class = storage_class; 360 this.type = type; 361 if (type) 362 { 363 // Normalize storage_class, because function-type related attributes 364 // are already set in the 'type' in parsing phase. 365 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); 366 } 367 this.endloc = endloc; 368 /* The type given for "infer the return type" is a TypeFunction with 369 * NULL for the return type. 370 */ 371 inferRetType = (type && type.nextOf() is null); 372 } 373 374 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type) 375 { 376 return new FuncDeclaration(loc, endloc, id, storage_class, type); 377 } 378 379 override Dsymbol syntaxCopy(Dsymbol s) 380 { 381 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); 382 FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); 383 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null; 384 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null; 385 f.fbody = fbody ? fbody.syntaxCopy() : null; 386 return f; 387 } 388 389 /**************************************************** 390 * Resolve forward reference of function signature - 391 * parameter types, return type, and attributes. 392 * Returns false if any errors exist in the signature. 393 */ 394 final bool functionSemantic() 395 { 396 if (!_scope) 397 return !errors; 398 399 this.cppnamespace = _scope.namespace; 400 401 if (!originalType) // semantic not yet run 402 { 403 TemplateInstance spec = isSpeculative(); 404 uint olderrs = global.errors; 405 uint oldgag = global.gag; 406 if (global.gag && !spec) 407 global.gag = 0; 408 dsymbolSemantic(this, _scope); 409 global.gag = oldgag; 410 if (spec && global.errors != olderrs) 411 spec.errors = (global.errors - olderrs != 0); 412 if (olderrs != global.errors) // if errors compiling this function 413 return false; 414 } 415 416 // if inferring return type, sematic3 needs to be run 417 // - When the function body contains any errors, we cannot assume 418 // the inferred return type is valid. 419 // So, the body errors should become the function signature error. 420 if (inferRetType && type && !type.nextOf()) 421 return functionSemantic3(); 422 423 TemplateInstance ti; 424 if (isInstantiated() && !isVirtualMethod() && 425 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) 426 { 427 AggregateDeclaration ad = isMemberLocal(); 428 if (ad && ad.sizeok != Sizeok.done) 429 { 430 /* Currently dmd cannot resolve forward references per methods, 431 * then setting SIZOKfwd is too conservative and would break existing code. 432 * So, just stop method attributes inference until ad.dsymbolSemantic() done. 433 */ 434 //ad.sizeok = Sizeok.fwd; 435 } 436 else 437 return functionSemantic3() || !errors; 438 } 439 440 if (storage_class & STC.inference) 441 return functionSemantic3() || !errors; 442 443 return !errors; 444 } 445 446 /**************************************************** 447 * Resolve forward reference of function body. 448 * Returns false if any errors exist in the body. 449 */ 450 final bool functionSemantic3() 451 { 452 if (semanticRun < PASS.semantic3 && _scope) 453 { 454 /* Forward reference - we need to run semantic3 on this function. 455 * If errors are gagged, and it's not part of a template instance, 456 * we need to temporarily ungag errors. 457 */ 458 TemplateInstance spec = isSpeculative(); 459 uint olderrs = global.errors; 460 uint oldgag = global.gag; 461 if (global.gag && !spec) 462 global.gag = 0; 463 semantic3(this, _scope); 464 global.gag = oldgag; 465 466 // If it is a speculatively-instantiated template, and errors occur, 467 // we need to mark the template as having errors. 468 if (spec && global.errors != olderrs) 469 spec.errors = (global.errors - olderrs != 0); 470 if (olderrs != global.errors) // if errors compiling this function 471 return false; 472 } 473 474 return !errors && !semantic3Errors; 475 } 476 477 /**************************************************** 478 * Check that this function type is properly resolved. 479 * If not, report "forward reference error" and return true. 480 */ 481 extern (D) final bool checkForwardRef(const ref Loc loc) 482 { 483 if (!functionSemantic()) 484 return true; 485 486 /* No deco means the functionSemantic() call could not resolve 487 * forward referenes in the type of this function. 488 */ 489 if (!type.deco) 490 { 491 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3); 492 .error(loc, "forward reference to %s`%s`", 493 (inSemantic3 ? "inferred return type of function " : "").ptr, 494 toChars()); 495 return true; 496 } 497 return false; 498 } 499 500 // called from semantic3 501 /** 502 * Creates and returns the hidden parameters for this function declaration. 503 * 504 * Hidden parameters include the `this` parameter of a class, struct or 505 * nested function and the selector parameter for Objective-C methods. 506 */ 507 extern (D) final void declareThis(Scope* sc) 508 { 509 isThis2 = toParent2() != toParentLocal(); 510 auto ad = isThis(); 511 if (!isThis2 && !ad && !isNested()) 512 { 513 vthis = null; 514 objc.selectorParameter = null; 515 return; 516 } 517 518 Type addModStc(Type t) 519 { 520 return t.addMod(type.mod).addStorageClass(storage_class); 521 } 522 523 if (isThis2 || isNested()) 524 { 525 /* The 'this' for a nested function is the link to the 526 * enclosing function's stack frame. 527 * Note that nested functions and member functions are disjoint. 528 */ 529 Type tthis = addModStc(isThis2 ? 530 Type.tvoidptr.sarrayOf(2).pointerTo() : 531 Type.tvoid.pointerTo()); 532 vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null); 533 vthis.storage_class |= STC.parameter | STC.nodtor; 534 } 535 else if (ad) 536 { 537 Type thandle = addModStc(ad.handleType()); 538 vthis = new ThisDeclaration(loc, thandle); 539 vthis.storage_class |= STC.parameter; 540 if (thandle.ty == Tstruct) 541 { 542 vthis.storage_class |= STC.ref_; 543 // if member function is marked 'inout', then 'this' is 'return ref' 544 if (type.ty == Tfunction && (cast(TypeFunction)type).isInOutQual()) 545 vthis.storage_class |= STC.return_; 546 } 547 } 548 549 if (type.ty == Tfunction) 550 { 551 TypeFunction tf = cast(TypeFunction)type; 552 if (tf.isreturn) 553 vthis.storage_class |= STC.return_; 554 if (tf.isScopeQual) 555 vthis.storage_class |= STC.scope_; 556 } 557 if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_)) 558 vthis.storage_class |= STC.maybescope; 559 560 vthis.dsymbolSemantic(sc); 561 if (!sc.insert(vthis)) 562 assert(0); 563 vthis.parent = this; 564 if (ad) 565 objc.selectorParameter = .objc.createSelectorParameter(this, sc); 566 } 567 568 override final bool equals(const RootObject o) const 569 { 570 if (this == o) 571 return true; 572 573 if (auto s = isDsymbol(o)) 574 { 575 auto fd1 = this; 576 auto fd2 = s.isFuncDeclaration(); 577 if (!fd2) 578 return false; 579 580 auto fa1 = fd1.isFuncAliasDeclaration(); 581 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1; 582 583 auto fa2 = fd2.isFuncAliasDeclaration(); 584 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2; 585 586 if (fa1 && fa2) 587 { 588 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads; 589 } 590 591 bool b1 = fa1 !is null; 592 if (b1 && faf1.isUnique() && !fa1.hasOverloads) 593 b1 = false; 594 595 bool b2 = fa2 !is null; 596 if (b2 && faf2.isUnique() && !fa2.hasOverloads) 597 b2 = false; 598 599 if (b1 != b2) 600 return false; 601 602 return faf1.toParent().equals(faf2.toParent()) && 603 faf1.ident.equals(faf2.ident) && 604 faf1.type.equals(faf2.type); 605 } 606 return false; 607 } 608 609 /**************************************************** 610 * Determine if 'this' overrides fd. 611 * Return !=0 if it does. 612 */ 613 final int overrides(FuncDeclaration fd) 614 { 615 int result = 0; 616 if (fd.ident == ident) 617 { 618 int cov = type.covariant(fd.type); 619 if (cov) 620 { 621 ClassDeclaration cd1 = toParent().isClassDeclaration(); 622 ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); 623 if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) 624 result = 1; 625 } 626 } 627 return result; 628 } 629 630 /************************************************* 631 * Find index of function in vtbl[0..dim] that 632 * this function overrides. 633 * Prefer an exact match to a covariant one. 634 * Params: 635 * vtbl = vtable to use 636 * dim = maximal vtable dimension 637 * Returns: 638 * -1 didn't find one 639 * -2 can't determine because of forward references 640 */ 641 final int findVtblIndex(Dsymbols* vtbl, int dim) 642 { 643 //printf("findVtblIndex() %s\n", toChars()); 644 FuncDeclaration mismatch = null; 645 StorageClass mismatchstc = 0; 646 int mismatchvi = -1; 647 int exactvi = -1; 648 int bestvi = -1; 649 for (int vi = 0; vi < dim; vi++) 650 { 651 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); 652 if (fdv && fdv.ident == ident) 653 { 654 if (type.equals(fdv.type)) // if exact match 655 { 656 if (fdv.parent.isClassDeclaration()) 657 { 658 if (fdv.isFuture()) 659 { 660 bestvi = vi; 661 continue; // keep looking 662 } 663 return vi; // no need to look further 664 } 665 666 if (exactvi >= 0) 667 { 668 error("cannot determine overridden function"); 669 return exactvi; 670 } 671 exactvi = vi; 672 bestvi = vi; 673 continue; 674 } 675 676 StorageClass stc = 0; 677 int cov = type.covariant(fdv.type, &stc); 678 //printf("\tbaseclass cov = %d\n", cov); 679 switch (cov) 680 { 681 case 0: 682 // types are distinct 683 break; 684 685 case 1: 686 bestvi = vi; // covariant, but not identical 687 break; 688 // keep looking for an exact match 689 690 case 2: 691 mismatchvi = vi; 692 mismatchstc = stc; 693 mismatch = fdv; // overrides, but is not covariant 694 break; 695 // keep looking for an exact match 696 697 case 3: 698 return -2; // forward references 699 700 default: 701 assert(0); 702 } 703 } 704 } 705 if (bestvi == -1 && mismatch) 706 { 707 //type.print(); 708 //mismatch.type.print(); 709 //printf("%s %s\n", type.deco, mismatch.type.deco); 710 //printf("stc = %llx\n", mismatchstc); 711 if (mismatchstc) 712 { 713 // Fix it by modifying the type to add the storage classes 714 type = type.addStorageClass(mismatchstc); 715 bestvi = mismatchvi; 716 } 717 } 718 return bestvi; 719 } 720 721 /********************************* 722 * If function a function in a base class, 723 * return that base class. 724 * Returns: 725 * base class if overriding, null if not 726 */ 727 final BaseClass* overrideInterface() 728 { 729 if (ClassDeclaration cd = toParent2().isClassDeclaration()) 730 { 731 foreach (b; cd.interfaces) 732 { 733 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); 734 if (v >= 0) 735 return b; 736 } 737 } 738 return null; 739 } 740 741 /**************************************************** 742 * Overload this FuncDeclaration with the new one f. 743 * Return true if successful; i.e. no conflict. 744 */ 745 override bool overloadInsert(Dsymbol s) 746 { 747 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars()); 748 assert(s != this); 749 AliasDeclaration ad = s.isAliasDeclaration(); 750 if (ad) 751 { 752 if (overnext) 753 return overnext.overloadInsert(ad); 754 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof) 755 { 756 //printf("\tad = '%s'\n", ad.type.toChars()); 757 return false; 758 } 759 overnext = ad; 760 //printf("\ttrue: no conflict\n"); 761 return true; 762 } 763 TemplateDeclaration td = s.isTemplateDeclaration(); 764 if (td) 765 { 766 if (!td.funcroot) 767 td.funcroot = this; 768 if (overnext) 769 return overnext.overloadInsert(td); 770 overnext = td; 771 return true; 772 } 773 FuncDeclaration fd = s.isFuncDeclaration(); 774 if (!fd) 775 return false; 776 777 version (none) 778 { 779 /* Disable this check because: 780 * const void foo(); 781 * semantic() isn't run yet on foo(), so the const hasn't been 782 * applied yet. 783 */ 784 if (type) 785 { 786 printf("type = %s\n", type.toChars()); 787 printf("fd.type = %s\n", fd.type.toChars()); 788 } 789 // fd.type can be NULL for overloaded constructors 790 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration()) 791 { 792 //printf("\tfalse: conflict %s\n", kind()); 793 return false; 794 } 795 } 796 797 if (overnext) 798 { 799 td = overnext.isTemplateDeclaration(); 800 if (td) 801 fd.overloadInsert(td); 802 else 803 return overnext.overloadInsert(fd); 804 } 805 overnext = fd; 806 //printf("\ttrue: no conflict\n"); 807 return true; 808 } 809 810 /******************************************** 811 * Find function in overload list that exactly matches t. 812 */ 813 extern (D) final FuncDeclaration overloadExactMatch(Type t) 814 { 815 FuncDeclaration fd; 816 overloadApply(this, (Dsymbol s) 817 { 818 auto f = s.isFuncDeclaration(); 819 if (!f) 820 return 0; 821 if (t.equals(f.type)) 822 { 823 fd = f; 824 return 1; 825 } 826 827 /* Allow covariant matches, as long as the return type 828 * is just a const conversion. 829 * This allows things like pure functions to match with an impure function type. 830 */ 831 if (t.ty == Tfunction) 832 { 833 auto tf = cast(TypeFunction)f.type; 834 if (tf.covariant(t) == 1 && 835 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) 836 { 837 fd = f; 838 return 1; 839 } 840 } 841 return 0; 842 }); 843 return fd; 844 } 845 846 /******************************************** 847 * Find function in overload list that matches to the 'this' modifier. 848 * There's four result types. 849 * 850 * 1. If the 'tthis' matches only one candidate, it's an "exact match". 851 * Returns the function and 'hasOverloads' is set to false. 852 * eg. If 'tthis" is mutable and there's only one mutable method. 853 * 2. If there's two or more match candidates, but a candidate function will be 854 * a "better match". 855 * Returns the better match function but 'hasOverloads' is set to true. 856 * eg. If 'tthis' is mutable, and there's both mutable and const methods, 857 * the mutable method will be a better match. 858 * 3. If there's two or more match candidates, but there's no better match, 859 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match". 860 * eg. If 'tthis' is mutable, and there's two or more mutable methods. 861 * 4. If there's no candidates, it's "no match" and returns null with error report. 862 * e.g. If 'tthis' is const but there's no const methods. 863 */ 864 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads) 865 { 866 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars()); 867 MatchAccumulator m; 868 overloadApply(this, (Dsymbol s) 869 { 870 auto f = s.isFuncDeclaration(); 871 if (!f || f == m.lastf) // skip duplicates 872 return 0; 873 874 auto tf = f.type.toTypeFunction(); 875 //printf("tf = %s\n", tf.toChars()); 876 877 MATCH match; 878 if (tthis) // non-static functions are preferred than static ones 879 { 880 if (f.needThis()) 881 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod); 882 else 883 match = MATCH.constant; // keep static function in overload candidates 884 } 885 else // static functions are preferred than non-static ones 886 { 887 if (f.needThis()) 888 match = MATCH.convert; 889 else 890 match = MATCH.exact; 891 } 892 if (match == MATCH.nomatch) 893 return 0; 894 895 if (match > m.last) goto LcurrIsBetter; 896 if (match < m.last) goto LlastIsBetter; 897 898 // See if one of the matches overrides the other. 899 if (m.lastf.overrides(f)) goto LlastIsBetter; 900 if (f.overrides(m.lastf)) goto LcurrIsBetter; 901 902 //printf("\tambiguous\n"); 903 m.nextf = f; 904 m.count++; 905 return 0; 906 907 LlastIsBetter: 908 //printf("\tlastbetter\n"); 909 m.count++; // count up 910 return 0; 911 912 LcurrIsBetter: 913 //printf("\tisbetter\n"); 914 if (m.last <= MATCH.convert) 915 { 916 // clear last secondary matching 917 m.nextf = null; 918 m.count = 0; 919 } 920 m.last = match; 921 m.lastf = f; 922 m.count++; // count up 923 return 0; 924 }); 925 926 if (m.count == 1) // exact match 927 { 928 hasOverloads = false; 929 } 930 else if (m.count > 1) // better or ambiguous match 931 { 932 hasOverloads = true; 933 } 934 else // no match 935 { 936 hasOverloads = true; 937 auto tf = this.type.toTypeFunction(); 938 assert(tthis); 939 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch 940 { 941 OutBuffer thisBuf, funcBuf; 942 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 943 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 944 .error(loc, "%smethod %s is not callable using a %sobject", 945 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars()); 946 } 947 } 948 return m.lastf; 949 } 950 951 /******************************************** 952 * find function template root in overload list 953 */ 954 extern (D) final TemplateDeclaration findTemplateDeclRoot() 955 { 956 FuncDeclaration f = this; 957 while (f && f.overnext) 958 { 959 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars()); 960 TemplateDeclaration td = f.overnext.isTemplateDeclaration(); 961 if (td) 962 return td; 963 f = f.overnext.isFuncDeclaration(); 964 } 965 return null; 966 } 967 968 /******************************************** 969 * Returns true if function was declared 970 * directly or indirectly in a unittest block 971 */ 972 final bool inUnittest() 973 { 974 Dsymbol f = this; 975 do 976 { 977 if (f.isUnitTestDeclaration()) 978 return true; 979 f = f.toParent(); 980 } 981 while (f); 982 return false; 983 } 984 985 /************************************* 986 * Determine partial specialization order of 'this' vs g. 987 * This is very similar to TemplateDeclaration::leastAsSpecialized(). 988 * Returns: 989 * match 'this' is at least as specialized as g 990 * 0 g is more specialized than 'this' 991 */ 992 final MATCH leastAsSpecialized(FuncDeclaration g) 993 { 994 enum LOG_LEASTAS = 0; 995 static if (LOG_LEASTAS) 996 { 997 printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); 998 printf("%s, %s\n", type.toChars(), g.type.toChars()); 999 } 1000 1001 /* This works by calling g() with f()'s parameters, and 1002 * if that is possible, then f() is at least as specialized 1003 * as g() is. 1004 */ 1005 1006 TypeFunction tf = type.toTypeFunction(); 1007 TypeFunction tg = g.type.toTypeFunction(); 1008 1009 /* If both functions have a 'this' pointer, and the mods are not 1010 * the same and g's is not const, then this is less specialized. 1011 */ 1012 if (needThis() && g.needThis() && tf.mod != tg.mod) 1013 { 1014 if (isCtorDeclaration()) 1015 { 1016 if (!MODimplicitConv(tg.mod, tf.mod)) 1017 return MATCH.nomatch; 1018 } 1019 else 1020 { 1021 if (!MODimplicitConv(tf.mod, tg.mod)) 1022 return MATCH.nomatch; 1023 } 1024 } 1025 1026 /* Create a dummy array of arguments out of the parameters to f() 1027 */ 1028 Expressions args; 1029 foreach (u, p; tf.parameterList) 1030 { 1031 Expression e; 1032 if (p.isReference()) 1033 { 1034 e = new IdentifierExp(Loc.initial, p.ident); 1035 e.type = p.type; 1036 } 1037 else 1038 e = p.type.defaultInitLiteral(Loc.initial); 1039 args.push(e); 1040 } 1041 1042 MATCH m = tg.callMatch(null, args[], 1); 1043 if (m > MATCH.nomatch) 1044 { 1045 /* A variadic parameter list is less specialized than a 1046 * non-variadic one. 1047 */ 1048 if (tf.parameterList.varargs && !tg.parameterList.varargs) 1049 goto L1; // less specialized 1050 1051 static if (LOG_LEASTAS) 1052 { 1053 printf(" matches %d, so is least as specialized\n", m); 1054 } 1055 return m; 1056 } 1057 L1: 1058 static if (LOG_LEASTAS) 1059 { 1060 printf(" doesn't match, so is not as specialized\n"); 1061 } 1062 return MATCH.nomatch; 1063 } 1064 1065 /******************************** 1066 * Labels are in a separate scope, one per function. 1067 */ 1068 final LabelDsymbol searchLabel(Identifier ident) 1069 { 1070 Dsymbol s; 1071 if (!labtab) 1072 labtab = new DsymbolTable(); // guess we need one 1073 1074 s = labtab.lookup(ident); 1075 if (!s) 1076 { 1077 s = new LabelDsymbol(ident); 1078 labtab.insert(s); 1079 } 1080 return cast(LabelDsymbol)s; 1081 } 1082 1083 /***************************************** 1084 * Determine lexical level difference from `this` to nested function `fd`. 1085 * Params: 1086 * fd = target of call 1087 * intypeof = !=0 if inside typeof 1088 * Returns: 1089 * 0 same level 1090 * >0 decrease nesting by number 1091 * -1 increase nesting by 1 (`fd` is nested within `this`) 1092 * LevelError error, `this` cannot call `fd` 1093 */ 1094 final int getLevel(FuncDeclaration fd, int intypeof) 1095 { 1096 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars()); 1097 Dsymbol fdparent = fd.toParent2(); 1098 if (fdparent == this) 1099 return -1; 1100 1101 Dsymbol s = this; 1102 int level = 0; 1103 while (fd != s && fdparent != s.toParent2()) 1104 { 1105 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars()); 1106 if (auto thisfd = s.isFuncDeclaration()) 1107 { 1108 if (!thisfd.isNested() && !thisfd.vthis && !intypeof) 1109 return LevelError; 1110 } 1111 else 1112 { 1113 if (auto thiscd = s.isAggregateDeclaration()) 1114 { 1115 /* AggregateDeclaration::isNested returns true only when 1116 * it has a hidden pointer. 1117 * But, calling the function belongs unrelated lexical scope 1118 * is still allowed inside typeof. 1119 * 1120 * struct Map(alias fun) { 1121 * typeof({ return fun(); }) RetType; 1122 * // No member function makes Map struct 'not nested'. 1123 * } 1124 */ 1125 if (!thiscd.isNested() && !intypeof) 1126 return LevelError; 1127 } 1128 else 1129 return LevelError; 1130 } 1131 1132 s = s.toParentP(fd); 1133 assert(s); 1134 level++; 1135 } 1136 return level; 1137 } 1138 1139 /*********************************** 1140 * Determine lexical level difference from `this` to nested function `fd`. 1141 * Issue error if `this` cannot call `fd`. 1142 * 1143 * Params: 1144 * loc = location for error messages 1145 * sc = context 1146 * fd = target of call 1147 * decl = The `Declaration` that triggered this check. 1148 * Used to provide a better error message only. 1149 * Returns: 1150 * 0 same level 1151 * >0 decrease nesting by number 1152 * -1 increase nesting by 1 (`fd` is nested within 'this') 1153 * LevelError error 1154 */ 1155 final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd, 1156 Declaration decl) 1157 { 1158 int level = getLevel(fd, sc.intypeof); 1159 if (level != LevelError) 1160 return level; 1161 1162 // Don't give error if in template constraint 1163 if (!(sc.flags & SCOPE.constraint)) 1164 { 1165 const(char)* xstatic = isStatic() ? "`static` " : ""; 1166 // better diagnostics for static functions 1167 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`", 1168 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(), 1169 fd.toPrettyChars()); 1170 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars()); 1171 return LevelError; 1172 } 1173 return 1; 1174 } 1175 1176 enum LevelError = -2; 1177 1178 override const(char)* toPrettyChars(bool QualifyTypes = false) 1179 { 1180 if (isMain()) 1181 return "D main"; 1182 else 1183 return Dsymbol.toPrettyChars(QualifyTypes); 1184 } 1185 1186 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ 1187 final const(char)* toFullSignature() 1188 { 1189 OutBuffer buf; 1190 functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars()); 1191 return buf.extractChars(); 1192 } 1193 1194 final bool isMain() const 1195 { 1196 return ident == Id.main && linkage != LINK.c && !isMember() && !isNested(); 1197 } 1198 1199 final bool isCMain() const 1200 { 1201 return ident == Id.main && linkage == LINK.c && !isMember() && !isNested(); 1202 } 1203 1204 final bool isWinMain() const 1205 { 1206 //printf("FuncDeclaration::isWinMain() %s\n", toChars()); 1207 version (none) 1208 { 1209 bool x = ident == Id.WinMain && linkage != LINK.c && !isMember(); 1210 printf("%s\n", x ? "yes" : "no"); 1211 return x; 1212 } 1213 else 1214 { 1215 return ident == Id.WinMain && linkage != LINK.c && !isMember(); 1216 } 1217 } 1218 1219 final bool isDllMain() const 1220 { 1221 return ident == Id.DllMain && linkage != LINK.c && !isMember(); 1222 } 1223 1224 final bool isRtInit() const 1225 { 1226 return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested(); 1227 } 1228 1229 override final bool isExport() const 1230 { 1231 return protection.kind == Prot.Kind.export_; 1232 } 1233 1234 override final bool isImportedSymbol() const 1235 { 1236 //printf("isImportedSymbol()\n"); 1237 //printf("protection = %d\n", protection); 1238 return (protection.kind == Prot.Kind.export_) && !fbody; 1239 } 1240 1241 override final bool isCodeseg() const pure nothrow @nogc @safe 1242 { 1243 return true; // functions are always in the code segment 1244 } 1245 1246 override final bool isOverloadable() const 1247 { 1248 return true; // functions can be overloaded 1249 } 1250 1251 /*********************************** 1252 * Override so it can work even if semantic() hasn't yet 1253 * been run. 1254 */ 1255 override final bool isAbstract() 1256 { 1257 if (storage_class & STC.abstract_) 1258 return true; 1259 if (semanticRun >= PASS.semanticdone) 1260 return false; 1261 1262 if (_scope) 1263 { 1264 if (_scope.stc & STC.abstract_) 1265 return true; 1266 parent = _scope.parent; 1267 Dsymbol parent = toParent(); 1268 if (parent.isInterfaceDeclaration()) 1269 return true; 1270 } 1271 return false; 1272 } 1273 1274 /********************************** 1275 * Decide if attributes for this function can be inferred from examining 1276 * the function body. 1277 * Returns: 1278 * true if can 1279 */ 1280 final bool canInferAttributes(Scope* sc) 1281 { 1282 if (canInferAttributesOverride) 1283 return canInferAttributesOverride(this, sc, &canInferAttributesImpl); 1284 1285 return canInferAttributesImpl(sc); 1286 } 1287 1288 extern (D) final bool canInferAttributesImpl(Scope* sc) 1289 { 1290 if (!fbody) 1291 return false; 1292 1293 if (isVirtualMethod()) 1294 return false; // since they may be overridden 1295 1296 if (sc.func && 1297 /********** this is for backwards compatibility for the moment ********/ 1298 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated())) 1299 return true; 1300 1301 if (isFuncLiteralDeclaration() || // externs are not possible with literals 1302 (storage_class & STC.inference) || // do attribute inference 1303 (inferRetType && !isCtorDeclaration())) 1304 return true; 1305 1306 if (isInstantiated()) 1307 { 1308 auto ti = parent.isTemplateInstance(); 1309 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident) 1310 return true; 1311 } 1312 1313 return false; 1314 } 1315 1316 /***************************************** 1317 * Initialize for inferring the attributes of this function. 1318 */ 1319 final void initInferAttributes() 1320 { 1321 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars()); 1322 TypeFunction tf = type.toTypeFunction(); 1323 if (tf.purity == PURE.impure) // purity not specified 1324 flags |= FUNCFLAG.purityInprocess; 1325 1326 if (tf.trust == TRUST.default_) 1327 flags |= FUNCFLAG.safetyInprocess; 1328 1329 if (!tf.isnothrow) 1330 flags |= FUNCFLAG.nothrowInprocess; 1331 1332 if (!tf.isnogc) 1333 flags |= FUNCFLAG.nogcInprocess; 1334 1335 if (!isVirtual() || introducing) 1336 flags |= FUNCFLAG.returnInprocess; 1337 1338 // Initialize for inferring STC.scope_ 1339 if (global.params.vsafe) 1340 flags |= FUNCFLAG.inferScope; 1341 } 1342 1343 final PURE isPure() 1344 { 1345 //printf("FuncDeclaration::isPure() '%s'\n", toChars()); 1346 TypeFunction tf = type.toTypeFunction(); 1347 if (flags & FUNCFLAG.purityInprocess) 1348 setImpure(); 1349 if (tf.purity == PURE.fwdref) 1350 tf.purityLevel(); 1351 PURE purity = tf.purity; 1352 if (purity > PURE.weak && isNested()) 1353 purity = PURE.weak; 1354 if (purity > PURE.weak && needThis()) 1355 { 1356 // The attribute of the 'this' reference affects purity strength 1357 if (type.mod & MODFlags.immutable_) 1358 { 1359 } 1360 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_) 1361 purity = PURE.const_; 1362 else 1363 purity = PURE.weak; 1364 } 1365 tf.purity = purity; 1366 // ^ This rely on the current situation that every FuncDeclaration has a 1367 // unique TypeFunction. 1368 return purity; 1369 } 1370 1371 final PURE isPureBypassingInference() 1372 { 1373 if (flags & FUNCFLAG.purityInprocess) 1374 return PURE.fwdref; 1375 else 1376 return isPure(); 1377 } 1378 1379 /************************************** 1380 * The function is doing something impure, 1381 * so mark it as impure. 1382 * If there's a purity error, return true. 1383 */ 1384 extern (D) final bool setImpure() 1385 { 1386 if (flags & FUNCFLAG.purityInprocess) 1387 { 1388 flags &= ~FUNCFLAG.purityInprocess; 1389 if (fes) 1390 fes.func.setImpure(); 1391 } 1392 else if (isPure()) 1393 return true; 1394 return false; 1395 } 1396 1397 final bool isSafe() 1398 { 1399 if (flags & FUNCFLAG.safetyInprocess) 1400 setUnsafe(); 1401 return type.toTypeFunction().trust == TRUST.safe; 1402 } 1403 1404 final bool isSafeBypassingInference() 1405 { 1406 return !(flags & FUNCFLAG.safetyInprocess) && isSafe(); 1407 } 1408 1409 final bool isTrusted() 1410 { 1411 if (flags & FUNCFLAG.safetyInprocess) 1412 setUnsafe(); 1413 return type.toTypeFunction().trust == TRUST.trusted; 1414 } 1415 1416 /************************************** 1417 * The function is doing something unsafe, 1418 * so mark it as unsafe. 1419 * If there's a safe error, return true. 1420 */ 1421 extern (D) final bool setUnsafe() 1422 { 1423 if (flags & FUNCFLAG.safetyInprocess) 1424 { 1425 flags &= ~FUNCFLAG.safetyInprocess; 1426 type.toTypeFunction().trust = TRUST.system; 1427 if (fes) 1428 fes.func.setUnsafe(); 1429 } 1430 else if (isSafe()) 1431 return true; 1432 return false; 1433 } 1434 1435 final bool isNogc() 1436 { 1437 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); 1438 if (flags & FUNCFLAG.nogcInprocess) 1439 setGC(); 1440 return type.toTypeFunction().isnogc; 1441 } 1442 1443 final bool isNogcBypassingInference() 1444 { 1445 return !(flags & FUNCFLAG.nogcInprocess) && isNogc(); 1446 } 1447 1448 /************************************** 1449 * The function is doing something that may allocate with the GC, 1450 * so mark it as not nogc (not no-how). 1451 * Returns: 1452 * true if function is marked as @nogc, meaning a user error occurred 1453 */ 1454 extern (D) final bool setGC() 1455 { 1456 //printf("setGC() %s\n", toChars()); 1457 if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope) 1458 { 1459 this.semantic2(_scope); 1460 this.semantic3(_scope); 1461 } 1462 1463 if (flags & FUNCFLAG.nogcInprocess) 1464 { 1465 flags &= ~FUNCFLAG.nogcInprocess; 1466 type.toTypeFunction().isnogc = false; 1467 if (fes) 1468 fes.func.setGC(); 1469 } 1470 else if (isNogc()) 1471 return true; 1472 return false; 1473 } 1474 1475 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn) 1476 { 1477 if (!global.params.vgc) 1478 return; 1479 1480 Module m = getModule(); 1481 if (m && m.isRoot() && !inUnittest()) 1482 { 1483 message(loc, "vgc: %s", warn); 1484 } 1485 } 1486 1487 /******************************************** 1488 * See if pointers from function parameters, mutable globals, or uplevel functions 1489 * could leak into return value. 1490 * Returns: 1491 * true if the function return value is isolated from 1492 * any inputs to the function 1493 */ 1494 extern (D) final bool isReturnIsolated() 1495 { 1496 //printf("isReturnIsolated(this: %s)\n", this.toChars); 1497 TypeFunction tf = type.toTypeFunction(); 1498 assert(tf.next); 1499 1500 Type treti = tf.next; 1501 if (tf.isref) 1502 return isTypeIsolatedIndirect(treti); // check influence from parameters 1503 1504 return isTypeIsolated(treti); 1505 } 1506 1507 /******************** 1508 * See if pointers from function parameters, mutable globals, or uplevel functions 1509 * could leak into type `t`. 1510 * Params: 1511 * t = type to check if it is isolated 1512 * Returns: 1513 * true if `t` is isolated from 1514 * any inputs to the function 1515 */ 1516 extern (D) final bool isTypeIsolated(Type t) 1517 { 1518 StringTable!Type parentTypes; 1519 parentTypes._init(); 1520 return isTypeIsolated(t, parentTypes); 1521 } 1522 1523 ///ditto 1524 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes) 1525 { 1526 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars()); 1527 1528 t = t.baseElemOf(); 1529 switch (t.ty) 1530 { 1531 case Tarray: 1532 case Tpointer: 1533 return isTypeIsolatedIndirect(t.nextOf()); // go down one level 1534 1535 case Taarray: 1536 case Tclass: 1537 return isTypeIsolatedIndirect(t); 1538 1539 case Tstruct: 1540 /* Drill down and check the struct's fields 1541 */ 1542 auto sym = t.toDsymbol(null).isStructDeclaration(); 1543 const tName = t.toChars.toDString; 1544 const entry = parentTypes.insert(tName, t); 1545 if (entry == null) 1546 { 1547 //we've already seen this type in a parent, not isolated 1548 return false; 1549 } 1550 foreach (v; sym.fields) 1551 { 1552 Type tmi = v.type.addMod(t.mod); 1553 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n", 1554 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars()); 1555 if (!isTypeIsolated(tmi, parentTypes)) 1556 return false; 1557 } 1558 return true; 1559 1560 default: 1561 return true; 1562 } 1563 } 1564 1565 /******************************************** 1566 * Params: 1567 * t = type of object to test one level of indirection down 1568 * Returns: 1569 * true if an object typed `t` has no indirections 1570 * which could have come from the function's parameters, mutable 1571 * globals, or uplevel functions. 1572 */ 1573 private bool isTypeIsolatedIndirect(Type t) 1574 { 1575 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars()); 1576 assert(t); 1577 1578 /* Since `t` is one level down from an indirection, it could pick 1579 * up a reference to a mutable global or an outer function, so 1580 * return false. 1581 */ 1582 if (!isPureBypassingInference() || isNested()) 1583 return false; 1584 1585 TypeFunction tf = type.toTypeFunction(); 1586 1587 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars()); 1588 1589 foreach (i, fparam; tf.parameterList) 1590 { 1591 Type tp = fparam.type; 1592 if (!tp) 1593 continue; 1594 1595 if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_)) 1596 { 1597 if (!traverseIndirections(tp, t)) 1598 return false; 1599 continue; 1600 } 1601 1602 /* Goes down one level of indirection, then calls traverseIndirection() on 1603 * the result. 1604 * Returns: 1605 * true if t is isolated from tp 1606 */ 1607 static bool traverse(Type tp, Type t) 1608 { 1609 tp = tp.baseElemOf(); 1610 switch (tp.ty) 1611 { 1612 case Tarray: 1613 case Tpointer: 1614 return traverseIndirections(tp.nextOf(), t); 1615 1616 case Taarray: 1617 case Tclass: 1618 return traverseIndirections(tp, t); 1619 1620 case Tstruct: 1621 /* Drill down and check the struct's fields 1622 */ 1623 auto sym = tp.toDsymbol(null).isStructDeclaration(); 1624 foreach (v; sym.fields) 1625 { 1626 Type tprmi = v.type.addMod(tp.mod); 1627 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars()); 1628 if (!traverse(tprmi, t)) 1629 return false; 1630 } 1631 return true; 1632 1633 default: 1634 return true; 1635 } 1636 } 1637 1638 if (!traverse(tp, t)) 1639 return false; 1640 } 1641 // The 'this' reference is a parameter, too 1642 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis()) 1643 { 1644 Type tthis = ad.getType().addMod(tf.mod); 1645 //printf("\ttthis = %s\n", tthis.toChars()); 1646 if (!traverseIndirections(tthis, t)) 1647 return false; 1648 } 1649 1650 return true; 1651 } 1652 1653 /**************************************** 1654 * Determine if function needs a static frame pointer. 1655 * Returns: 1656 * `true` if function is really nested within other function. 1657 * Contracts: 1658 * If isNested() returns true, isThis() should return false, 1659 * unless the function needs a dual-context pointer. 1660 */ 1661 bool isNested() const 1662 { 1663 auto f = toAliasFunc(); 1664 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars()); 1665 return ((f.storage_class & STC.static_) == 0) && 1666 (f.linkage == LINK.d) && 1667 (f.toParent2().isFuncDeclaration() !is null || 1668 f.toParent2() !is f.toParentLocal()); 1669 } 1670 1671 /**************************************** 1672 * Determine if function is a non-static member function 1673 * that has an implicit 'this' expression. 1674 * Returns: 1675 * The aggregate it is a member of, or null. 1676 * Contracts: 1677 * Both isThis() and isNested() should return true if function needs a dual-context pointer, 1678 * otherwise if isThis() returns true, isNested() should return false. 1679 */ 1680 override inout(AggregateDeclaration) isThis() inout 1681 { 1682 //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); 1683 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal(); 1684 //printf("-FuncDeclaration::isThis() %p\n", ad); 1685 return ad; 1686 } 1687 1688 override final bool needThis() 1689 { 1690 //printf("FuncDeclaration::needThis() '%s'\n", toChars()); 1691 return toAliasFunc().isThis() !is null; 1692 } 1693 1694 // Determine if a function is pedantically virtual 1695 final bool isVirtualMethod() 1696 { 1697 if (toAliasFunc() != this) 1698 return toAliasFunc().isVirtualMethod(); 1699 1700 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); 1701 if (!isVirtual()) 1702 return false; 1703 // If it's a final method, and does not override anything, then it is not virtual 1704 if (isFinalFunc() && foverrides.dim == 0) 1705 { 1706 return false; 1707 } 1708 return true; 1709 } 1710 1711 // Determine if function goes into virtual function pointer table 1712 bool isVirtual() const 1713 { 1714 if (toAliasFunc() != this) 1715 return toAliasFunc().isVirtual(); 1716 1717 auto p = toParent(); 1718 1719 if (!isMember || !p.isClassDeclaration) 1720 return false; 1721 // https://issues.dlang.org/show_bug.cgi?id=19654 1722 if (p.isClassDeclaration.classKind == ClassKind.objc && !p.isInterfaceDeclaration) 1723 return .objc.isVirtual(this); 1724 1725 version (none) 1726 { 1727 printf("FuncDeclaration::isVirtual(%s)\n", toChars()); 1728 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == Prot.Kind.private_, isCtorDeclaration(), linkage != LINK.d); 1729 printf("result is %d\n", isMember() && !(isStatic() || protection == Prot.Kind.private_ || protection == Prot.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc())); 1730 } 1731 return !(isStatic() || protection.kind == Prot.Kind.private_ || protection.kind == Prot.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc()); 1732 } 1733 1734 final bool isFinalFunc() const 1735 { 1736 if (toAliasFunc() != this) 1737 return toAliasFunc().isFinalFunc(); 1738 1739 version (none) 1740 {{ 1741 auto cd = toParent().isClassDeclaration(); 1742 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal()); 1743 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_)); 1744 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_))); 1745 if (cd) 1746 printf("\tmember of %s\n", cd.toChars()); 1747 }} 1748 if (!isMember()) 1749 return false; 1750 if (Declaration.isFinal()) 1751 return true; 1752 auto cd = toParent().isClassDeclaration(); 1753 return (cd !is null) && (cd.storage_class & STC.final_); 1754 } 1755 1756 bool addPreInvariant() 1757 { 1758 auto ad = isThis(); 1759 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 1760 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); 1761 } 1762 1763 bool addPostInvariant() 1764 { 1765 auto ad = isThis(); 1766 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 1767 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); 1768 } 1769 1770 override const(char)* kind() const 1771 { 1772 return generated ? "generated function" : "function"; 1773 } 1774 1775 /******************************************** 1776 * Returns: 1777 * true if there are no overloads of this function 1778 */ 1779 final bool isUnique() const 1780 { 1781 bool result = false; 1782 overloadApply(cast() this, (Dsymbol s) 1783 { 1784 auto f = s.isFuncDeclaration(); 1785 if (!f) 1786 return 0; 1787 if (result) 1788 { 1789 result = false; 1790 return 1; // ambiguous, done 1791 } 1792 else 1793 { 1794 result = true; 1795 return 0; 1796 } 1797 }); 1798 return result; 1799 } 1800 1801 /********************************************* 1802 * In the current function, we are calling 'this' function. 1803 * 1. Check to see if the current function can call 'this' function, issue error if not. 1804 * 2. If the current function is not the parent of 'this' function, then add 1805 * the current function to the list of siblings of 'this' function. 1806 * 3. If the current function is a literal, and it's accessing an uplevel scope, 1807 * then mark it as a delegate. 1808 * Returns true if error occurs. 1809 */ 1810 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc) 1811 { 1812 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars()); 1813 1814 if (auto fld = this.isFuncLiteralDeclaration()) 1815 { 1816 if (fld.tok == TOK.reserved) 1817 { 1818 fld.tok = TOK.function_; 1819 fld.vthis = null; 1820 } 1821 } 1822 1823 if (!parent || parent == sc.parent) 1824 return false; 1825 if (ident == Id.require || ident == Id.ensure) 1826 return false; 1827 if (!isThis() && !isNested()) 1828 return false; 1829 1830 // The current function 1831 FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); 1832 if (!fdthis) 1833 return false; // out of function scope 1834 1835 Dsymbol p = toParentLocal(); 1836 Dsymbol p2 = toParent2(); 1837 1838 // Function literals from fdthis to p must be delegates 1839 ensureStaticLinkTo(fdthis, p); 1840 if (p != p2) 1841 ensureStaticLinkTo(fdthis, p2); 1842 1843 if (isNested()) 1844 { 1845 // The function that this function is in 1846 bool checkEnclosing(FuncDeclaration fdv) 1847 { 1848 if (!fdv) 1849 return false; 1850 if (fdv == fdthis) 1851 return false; 1852 1853 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars()); 1854 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars()); 1855 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars()); 1856 1857 // Add this function to the list of those which called us 1858 if (fdthis != this) 1859 { 1860 bool found = false; 1861 for (size_t i = 0; i < siblingCallers.dim; ++i) 1862 { 1863 if (siblingCallers[i] == fdthis) 1864 found = true; 1865 } 1866 if (!found) 1867 { 1868 //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); 1869 if (!sc.intypeof && !(sc.flags & SCOPE.compile)) 1870 siblingCallers.push(fdthis); 1871 } 1872 } 1873 1874 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this); 1875 if (lv == LevelError) 1876 return true; // error 1877 if (lv == -1) 1878 return false; // downlevel call 1879 if (lv == 0) 1880 return false; // same level call 1881 1882 return false; // Uplevel call 1883 } 1884 1885 if (checkEnclosing(p.isFuncDeclaration())) 1886 return true; 1887 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration())) 1888 return true; 1889 } 1890 return false; 1891 } 1892 1893 /******************************* 1894 * Look at all the variables in this function that are referenced 1895 * by nested functions, and determine if a closure needs to be 1896 * created for them. 1897 */ 1898 final bool needsClosure() 1899 { 1900 /* Need a closure for all the closureVars[] if any of the 1901 * closureVars[] are accessed by a 1902 * function that escapes the scope of this function. 1903 * We take the conservative approach and decide that a function needs 1904 * a closure if it: 1905 * 1) is a virtual function 1906 * 2) has its address taken 1907 * 3) has a parent that escapes 1908 * 4) calls another nested function that needs a closure 1909 * 1910 * Note that since a non-virtual function can be called by 1911 * a virtual one, if that non-virtual function accesses a closure 1912 * var, the closure still has to be taken. Hence, we check for isThis() 1913 * instead of isVirtual(). (thanks to David Friedman) 1914 * 1915 * When the function returns a local struct or class, `requiresClosure` 1916 * is already set to `true` upon entering this function when the 1917 * struct/class refers to a local variable and a closure is needed. 1918 */ 1919 1920 //printf("FuncDeclaration::needsClosure() %s\n", toChars()); 1921 1922 if (requiresClosure) 1923 goto Lyes; 1924 1925 for (size_t i = 0; i < closureVars.dim; i++) 1926 { 1927 VarDeclaration v = closureVars[i]; 1928 //printf("\tv = %s\n", v.toChars()); 1929 1930 for (size_t j = 0; j < v.nestedrefs.dim; j++) 1931 { 1932 FuncDeclaration f = v.nestedrefs[j]; 1933 assert(f != this); 1934 1935 /* __require and __ensure will always get called directly, 1936 * so they never make outer functions closure. 1937 */ 1938 if (f.ident == Id.require || f.ident == Id.ensure) 1939 continue; 1940 1941 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf); 1942 1943 /* Look to see if f escapes. We consider all parents of f within 1944 * this, and also all siblings which call f; if any of them escape, 1945 * so does f. 1946 * Mark all affected functions as requiring closures. 1947 */ 1948 for (Dsymbol s = f; s && s != this; s = s.toParentP(this)) 1949 { 1950 FuncDeclaration fx = s.isFuncDeclaration(); 1951 if (!fx) 1952 continue; 1953 if (fx.isThis() || fx.tookAddressOf) 1954 { 1955 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf); 1956 1957 /* Mark as needing closure any functions between this and f 1958 */ 1959 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this); 1960 1961 requiresClosure = true; 1962 } 1963 1964 /* We also need to check if any sibling functions that 1965 * called us, have escaped. This is recursive: we need 1966 * to check the callers of our siblings. 1967 */ 1968 if (checkEscapingSiblings(fx, this)) 1969 requiresClosure = true; 1970 1971 /* https://issues.dlang.org/show_bug.cgi?id=12406 1972 * Iterate all closureVars to mark all descendant 1973 * nested functions that access to the closing context of this function. 1974 */ 1975 } 1976 } 1977 } 1978 if (requiresClosure) 1979 goto Lyes; 1980 1981 return false; 1982 1983 Lyes: 1984 //printf("\tneeds closure\n"); 1985 return true; 1986 } 1987 1988 /*********************************************** 1989 * Check that the function contains any closure. 1990 * If it's @nogc, report suitable errors. 1991 * This is mostly consistent with FuncDeclaration::needsClosure(). 1992 * 1993 * Returns: 1994 * true if any errors occur. 1995 */ 1996 extern (D) final bool checkClosure() 1997 { 1998 if (!needsClosure()) 1999 return false; 2000 2001 if (setGC()) 2002 { 2003 error("is `@nogc` yet allocates closures with the GC"); 2004 if (global.gag) // need not report supplemental errors 2005 return true; 2006 } 2007 else 2008 { 2009 printGCUsage(loc, "using closure causes GC allocation"); 2010 return false; 2011 } 2012 2013 FuncDeclarations a; 2014 foreach (v; closureVars) 2015 { 2016 foreach (f; v.nestedrefs) 2017 { 2018 assert(f !is this); 2019 2020 LcheckAncestorsOfANestedRef: 2021 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this)) 2022 { 2023 auto fx = s.isFuncDeclaration(); 2024 if (!fx) 2025 continue; 2026 if (fx.isThis() || 2027 fx.tookAddressOf || 2028 checkEscapingSiblings(fx, this)) 2029 { 2030 foreach (f2; a) 2031 { 2032 if (f2 == f) 2033 break LcheckAncestorsOfANestedRef; 2034 } 2035 a.push(f); 2036 .errorSupplemental(f.loc, "%s closes over variable %s at %s", 2037 f.toPrettyChars(), v.toChars(), v.loc.toChars()); 2038 break LcheckAncestorsOfANestedRef; 2039 } 2040 } 2041 } 2042 } 2043 2044 return true; 2045 } 2046 2047 /*********************************************** 2048 * Determine if function's variables are referenced by a function 2049 * nested within it. 2050 */ 2051 final bool hasNestedFrameRefs() 2052 { 2053 if (closureVars.dim) 2054 return true; 2055 2056 /* If a virtual function has contracts, assume its variables are referenced 2057 * by those contracts, even if they aren't. Because they might be referenced 2058 * by the overridden or overriding function's contracts. 2059 * This can happen because frequire and fensure are implemented as nested functions, 2060 * and they can be called directly by an overriding function and the overriding function's 2061 * context had better match, or 2062 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite. 2063 */ 2064 if (fdrequire || fdensure) 2065 return true; 2066 2067 if (foverrides.dim && isVirtualMethod()) 2068 { 2069 for (size_t i = 0; i < foverrides.dim; i++) 2070 { 2071 FuncDeclaration fdv = foverrides[i]; 2072 if (fdv.hasNestedFrameRefs()) 2073 return true; 2074 } 2075 } 2076 return false; 2077 } 2078 2079 /**************************************************** 2080 * Check whether result variable can be built. 2081 * Returns: 2082 * `true` if the function has a return type that 2083 * is different from `void`. 2084 */ 2085 extern (D) private bool canBuildResultVar() 2086 { 2087 auto f = cast(TypeFunction)type; 2088 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid; 2089 } 2090 2091 /**************************************************** 2092 * Declare result variable lazily. 2093 */ 2094 extern (D) final void buildResultVar(Scope* sc, Type tret) 2095 { 2096 if (!vresult) 2097 { 2098 Loc loc = fensure ? fensure.loc : this.loc; 2099 2100 /* If inferRetType is true, tret may not be a correct return type yet. 2101 * So, in here it may be a temporary type for vresult, and after 2102 * fbody.dsymbolSemantic() running, vresult.type might be modified. 2103 */ 2104 vresult = new VarDeclaration(loc, tret, Id.result, null); 2105 vresult.storage_class |= STC.nodtor | STC.temp; 2106 if (!isVirtual()) 2107 vresult.storage_class |= STC.const_; 2108 vresult.storage_class |= STC.result; 2109 2110 // set before the semantic() for checkNestedReference() 2111 vresult.parent = this; 2112 } 2113 2114 if (sc && vresult.semanticRun == PASS.init) 2115 { 2116 TypeFunction tf = type.toTypeFunction(); 2117 if (tf.isref) 2118 vresult.storage_class |= STC.ref_; 2119 vresult.type = tret; 2120 2121 vresult.dsymbolSemantic(sc); 2122 2123 if (!sc.insert(vresult)) 2124 error("out result %s is already defined", vresult.toChars()); 2125 assert(vresult.parent == this); 2126 } 2127 } 2128 2129 /**************************************************** 2130 * Merge into this function the 'in' contracts of all it overrides. 2131 * 'in's are OR'd together, i.e. only one of them needs to pass. 2132 */ 2133 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params) 2134 { 2135 /* If a base function and its override both have an IN contract, then 2136 * only one of them needs to succeed. This is done by generating: 2137 * 2138 * void derived.in() { 2139 * try { 2140 * base.in(); 2141 * } 2142 * catch () { 2143 * ... body of derived.in() ... 2144 * } 2145 * } 2146 * 2147 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid. 2148 * If base.in() throws, then derived.in()'s body is executed. 2149 */ 2150 2151 foreach (fdv; foverrides) 2152 { 2153 /* The semantic pass on the contracts of the overridden functions must 2154 * be completed before code generation occurs. 2155 * https://issues.dlang.org/show_bug.cgi?id=3602 2156 */ 2157 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done) 2158 { 2159 assert(fdv._scope); 2160 Scope* sc = fdv._scope.push(); 2161 sc.stc &= ~STC.override_; 2162 fdv.semantic3(sc); 2163 sc.pop(); 2164 } 2165 2166 sf = fdv.mergeFrequire(sf, params); 2167 if (sf && fdv.fdrequire) 2168 { 2169 //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); 2170 /* Make the call: 2171 * try { __require(params); } 2172 * catch (Throwable) { frequire; } 2173 */ 2174 params = Expression.arraySyntaxCopy(params); 2175 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params); 2176 Statement s2 = new ExpStatement(loc, e); 2177 2178 auto c = new Catch(loc, getThrowable(), null, sf); 2179 c.internalCatch = true; 2180 auto catches = new Catches(); 2181 catches.push(c); 2182 sf = new TryCatchStatement(loc, s2, catches); 2183 } 2184 else 2185 return null; 2186 } 2187 return sf; 2188 } 2189 2190 /**************************************************** 2191 * Determine whether an 'out' contract is declared inside 2192 * the given function or any of its overrides. 2193 * Params: 2194 * fd = the function to search 2195 * Returns: 2196 * true found an 'out' contract 2197 */ 2198 static bool needsFensure(FuncDeclaration fd) 2199 { 2200 if (fd.fensures) 2201 return true; 2202 2203 foreach (fdv; fd.foverrides) 2204 { 2205 if (needsFensure(fdv)) 2206 return true; 2207 } 2208 return false; 2209 } 2210 2211 /**************************************************** 2212 * Rewrite contracts as statements. 2213 */ 2214 final void buildEnsureRequire() 2215 { 2216 2217 if (frequires) 2218 { 2219 /* in { statements1... } 2220 * in { statements2... } 2221 * ... 2222 * becomes: 2223 * in { { statements1... } { statements2... } ... } 2224 */ 2225 assert(frequires.dim); 2226 auto loc = (*frequires)[0].loc; 2227 auto s = new Statements; 2228 foreach (r; *frequires) 2229 { 2230 s.push(new ScopeStatement(r.loc, r, r.loc)); 2231 } 2232 frequire = new CompoundStatement(loc, s); 2233 } 2234 2235 if (fensures) 2236 { 2237 /* out(id1) { statements1... } 2238 * out(id2) { statements2... } 2239 * ... 2240 * becomes: 2241 * out(__result) { { ref id1 = __result; { statements1... } } 2242 * { ref id2 = __result; { statements2... } } ... } 2243 */ 2244 assert(fensures.dim); 2245 auto loc = (*fensures)[0].ensure.loc; 2246 auto s = new Statements; 2247 foreach (r; *fensures) 2248 { 2249 if (r.id && canBuildResultVar()) 2250 { 2251 auto rloc = r.ensure.loc; 2252 auto resultId = new IdentifierExp(rloc, Id.result); 2253 auto init = new ExpInitializer(rloc, resultId); 2254 auto stc = STC.ref_ | STC.temp | STC.result; 2255 auto decl = new VarDeclaration(rloc, null, r.id, init, stc); 2256 auto sdecl = new ExpStatement(rloc, decl); 2257 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc)); 2258 } 2259 else 2260 { 2261 s.push(r.ensure); 2262 } 2263 } 2264 fensure = new CompoundStatement(loc, s); 2265 } 2266 2267 if (!isVirtual()) 2268 return; 2269 2270 /* Rewrite contracts as nested functions, then call them. Doing it as nested 2271 * functions means that overriding functions can call them. 2272 */ 2273 TypeFunction f = cast(TypeFunction) type; 2274 2275 /* Make a copy of the parameters and make them all ref */ 2276 static Parameters* toRefCopy(ParameterList parameterList) 2277 { 2278 auto result = new Parameters(); 2279 2280 foreach (n, p; parameterList) 2281 { 2282 p = p.syntaxCopy(); 2283 if (!(p.storageClass & STC.lazy_)) 2284 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_; 2285 p.defaultArg = null; // won't be the same with ref 2286 result.push(p); 2287 } 2288 2289 return result; 2290 } 2291 2292 if (frequire) 2293 { 2294 /* in { ... } 2295 * becomes: 2296 * void __require(ref params) { ... } 2297 * __require(params); 2298 */ 2299 Loc loc = frequire.loc; 2300 fdrequireParams = new Expressions(); 2301 if (parameters) 2302 { 2303 foreach (vd; *parameters) 2304 fdrequireParams.push(new VarExp(loc, vd)); 2305 } 2306 auto fo = cast(TypeFunction)(originalType ? originalType : f); 2307 auto fparams = toRefCopy(fo.parameterList); 2308 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d); 2309 tf.isnothrow = f.isnothrow; 2310 tf.isnogc = f.isnogc; 2311 tf.purity = f.purity; 2312 tf.trust = f.trust; 2313 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf); 2314 fd.fbody = frequire; 2315 Statement s1 = new ExpStatement(loc, fd); 2316 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams); 2317 Statement s2 = new ExpStatement(loc, e); 2318 frequire = new CompoundStatement(loc, s1, s2); 2319 fdrequire = fd; 2320 } 2321 2322 /* We need to set fdensureParams here and not in the block below to 2323 * have the parameters available when calling a base class ensure(), 2324 * even if this function doesn't have an out contract. 2325 */ 2326 fdensureParams = new Expressions(); 2327 if (canBuildResultVar()) 2328 fdensureParams.push(new IdentifierExp(loc, Id.result)); 2329 if (parameters) 2330 { 2331 foreach (vd; *parameters) 2332 fdensureParams.push(new VarExp(loc, vd)); 2333 } 2334 2335 if (fensure) 2336 { 2337 /* out (result) { ... } 2338 * becomes: 2339 * void __ensure(ref tret result, ref params) { ... } 2340 * __ensure(result, params); 2341 */ 2342 Loc loc = fensure.loc; 2343 auto fparams = new Parameters(); 2344 if (canBuildResultVar()) 2345 { 2346 Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null); 2347 fparams.push(p); 2348 } 2349 auto fo = cast(TypeFunction)(originalType ? originalType : f); 2350 fparams.pushSlice((*toRefCopy(fo.parameterList))[]); 2351 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d); 2352 tf.isnothrow = f.isnothrow; 2353 tf.isnogc = f.isnogc; 2354 tf.purity = f.purity; 2355 tf.trust = f.trust; 2356 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf); 2357 fd.fbody = fensure; 2358 Statement s1 = new ExpStatement(loc, fd); 2359 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams); 2360 Statement s2 = new ExpStatement(loc, e); 2361 fensure = new CompoundStatement(loc, s1, s2); 2362 fdensure = fd; 2363 } 2364 } 2365 2366 /**************************************************** 2367 * Merge into this function the 'out' contracts of all it overrides. 2368 * 'out's are AND'd together, i.e. all of them need to pass. 2369 */ 2370 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params) 2371 { 2372 /* Same comments as for mergeFrequire(), except that we take care 2373 * of generating a consistent reference to the 'result' local by 2374 * explicitly passing 'result' to the nested function as a reference 2375 * argument. 2376 * This won't work for the 'this' parameter as it would require changing 2377 * the semantic code for the nested function so that it looks on the parameter 2378 * list for the 'this' pointer, something that would need an unknown amount 2379 * of tweaking of various parts of the compiler that I'd rather leave alone. 2380 */ 2381 foreach (fdv; foverrides) 2382 { 2383 /* The semantic pass on the contracts of the overridden functions must 2384 * be completed before code generation occurs. 2385 * https://issues.dlang.org/show_bug.cgi?id=3602 and 2386 * https://issues.dlang.org/show_bug.cgi?id=5230 2387 */ 2388 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done) 2389 { 2390 assert(fdv._scope); 2391 Scope* sc = fdv._scope.push(); 2392 sc.stc &= ~STC.override_; 2393 fdv.semantic3(sc); 2394 sc.pop(); 2395 } 2396 2397 sf = fdv.mergeFensure(sf, oid, params); 2398 if (fdv.fdensure) 2399 { 2400 //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); 2401 // Make the call: __ensure(result, params) 2402 params = Expression.arraySyntaxCopy(params); 2403 if (canBuildResultVar()) 2404 { 2405 Type t1 = fdv.type.nextOf().toBasetype(); 2406 Type t2 = this.type.nextOf().toBasetype(); 2407 if (t1.isBaseOf(t2, null)) 2408 { 2409 /* Making temporary reference variable is necessary 2410 * in covariant return. 2411 * https://issues.dlang.org/show_bug.cgi?id=5204 2412 * https://issues.dlang.org/show_bug.cgi?id=10479 2413 */ 2414 Expression* eresult = &(*params)[0]; 2415 auto ei = new ExpInitializer(Loc.initial, *eresult); 2416 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei); 2417 v.storage_class |= STC.temp; 2418 auto de = new DeclarationExp(Loc.initial, v); 2419 auto ve = new VarExp(Loc.initial, v); 2420 *eresult = new CommaExp(Loc.initial, de, ve); 2421 } 2422 } 2423 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params); 2424 Statement s2 = new ExpStatement(loc, e); 2425 2426 if (sf) 2427 { 2428 sf = new CompoundStatement(sf.loc, s2, sf); 2429 } 2430 else 2431 sf = s2; 2432 } 2433 } 2434 return sf; 2435 } 2436 2437 /********************************************* 2438 * Returns: the function's parameter list, and whether 2439 * it is variadic or not. 2440 */ 2441 final ParameterList getParameterList() 2442 { 2443 if (type) 2444 { 2445 TypeFunction fdtype = type.isTypeFunction(); 2446 return fdtype.parameterList; 2447 } 2448 2449 return ParameterList(null, VarArg.none); 2450 } 2451 2452 /********************************** 2453 * Generate a FuncDeclaration for a runtime library function. 2454 */ 2455 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) 2456 { 2457 return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc); 2458 } 2459 2460 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) 2461 { 2462 FuncDeclaration fd; 2463 TypeFunction tf; 2464 Dsymbol s; 2465 __gshared DsymbolTable st = null; 2466 2467 //printf("genCfunc(name = '%s')\n", id.toChars()); 2468 //printf("treturn\n\t"); treturn.print(); 2469 2470 // See if already in table 2471 if (!st) 2472 st = new DsymbolTable(); 2473 s = st.lookup(id); 2474 if (s) 2475 { 2476 fd = s.isFuncDeclaration(); 2477 assert(fd); 2478 assert(fd.type.nextOf().equals(treturn)); 2479 } 2480 else 2481 { 2482 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc); 2483 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf); 2484 fd.protection = Prot(Prot.Kind.public_); 2485 fd.linkage = LINK.c; 2486 2487 st.insert(fd); 2488 } 2489 return fd; 2490 } 2491 2492 /****************** 2493 * Check parameters and return type of D main() function. 2494 * Issue error messages. 2495 */ 2496 extern (D) final void checkDmain() 2497 { 2498 TypeFunction tf = type.toTypeFunction(); 2499 const nparams = tf.parameterList.length; 2500 bool argerr; 2501 if (nparams == 1) 2502 { 2503 auto fparam0 = tf.parameterList[0]; 2504 auto t = fparam0.type.toBasetype(); 2505 if (t.ty != Tarray || 2506 t.nextOf().ty != Tarray || 2507 t.nextOf().nextOf().ty != Tchar || 2508 fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_)) 2509 { 2510 argerr = true; 2511 } 2512 } 2513 2514 if (!tf.nextOf()) 2515 error("must return `int` or `void`"); 2516 else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid) 2517 error("must return `int` or `void`, not `%s`", tf.nextOf().toChars()); 2518 else if (tf.parameterList.varargs || nparams >= 2 || argerr) 2519 error("parameters must be `main()` or `main(string[] args)`"); 2520 } 2521 2522 /*********************************************** 2523 * Check all return statements for a function to verify that returning 2524 * using NRVO is possible. 2525 * 2526 * Returns: 2527 * true if the result cannot be returned by hidden reference. 2528 */ 2529 final bool checkNrvo() 2530 { 2531 if (!nrvo_can) 2532 return true; 2533 2534 if (returns is null) 2535 return true; 2536 2537 auto tf = type.toTypeFunction(); 2538 if (tf.isref) 2539 return true; 2540 2541 foreach (rs; *returns) 2542 { 2543 if (auto ve = rs.exp.isVarExp()) 2544 { 2545 auto v = ve.var.isVarDeclaration(); 2546 if (!v || v.isOut() || v.isRef()) 2547 return true; 2548 else if (nrvo_var is null) 2549 { 2550 if (!v.isDataseg() && !v.isParameter() && v.toParent2() == this) 2551 { 2552 //printf("Setting nrvo to %s\n", v.toChars()); 2553 nrvo_var = v; 2554 } 2555 else 2556 return true; 2557 } 2558 else if (nrvo_var != v) 2559 return true; 2560 } 2561 else //if (!exp.isLvalue()) // keep NRVO-ability 2562 return true; 2563 } 2564 return false; 2565 } 2566 2567 override final inout(FuncDeclaration) isFuncDeclaration() inout 2568 { 2569 return this; 2570 } 2571 2572 inout(FuncDeclaration) toAliasFunc() inout 2573 { 2574 return this; 2575 } 2576 2577 override void accept(Visitor v) 2578 { 2579 v.visit(this); 2580 } 2581 } 2582 2583 /******************************************************** 2584 * Generate Expression to call the invariant. 2585 * Input: 2586 * ad aggregate with the invariant 2587 * vthis variable with 'this' 2588 * Returns: 2589 * void expression that calls the invariant 2590 */ 2591 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) 2592 { 2593 Expression e = null; 2594 // Call invariant directly only if it exists 2595 FuncDeclaration inv = ad.inv; 2596 ClassDeclaration cd = ad.isClassDeclaration(); 2597 2598 while (!inv && cd) 2599 { 2600 cd = cd.baseClass; 2601 if (!cd) 2602 break; 2603 inv = cd.inv; 2604 } 2605 if (inv) 2606 { 2607 version (all) 2608 { 2609 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 2610 // For the correct mangling, 2611 // run attribute inference on inv if needed. 2612 inv.functionSemantic(); 2613 } 2614 2615 //e = new DsymbolExp(Loc.initial, inv); 2616 //e = new CallExp(Loc.initial, e); 2617 //e = e.semantic(sc2); 2618 2619 /* https://issues.dlang.org/show_bug.cgi?id=13113 2620 * Currently virtual invariant calls completely 2621 * bypass attribute enforcement. 2622 * Change the behavior of pre-invariant call by following it. 2623 */ 2624 e = new ThisExp(Loc.initial); 2625 e.type = ad.type.addMod(vthis.type.mod); 2626 e = new DotVarExp(Loc.initial, e, inv, false); 2627 e.type = inv.type; 2628 e = new CallExp(Loc.initial, e); 2629 e.type = Type.tvoid; 2630 } 2631 return e; 2632 } 2633 2634 /*************************************************** 2635 * Visit each overloaded function/template in turn, and call dg(s) on it. 2636 * Exit when no more, or dg(s) returns nonzero. 2637 * 2638 * Params: 2639 * fstart = symbol to start from 2640 * dg = the delegate to be called on the overload 2641 * sc = context used to check if symbol is accessible (and therefore visible), 2642 * can be null 2643 * 2644 * Returns: 2645 * ==0 continue 2646 * !=0 done (and the return value from the last dg() call) 2647 */ 2648 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null) 2649 { 2650 Dsymbol next; 2651 for (auto d = fstart; d; d = next) 2652 { 2653 import dmd.access : checkSymbolAccess; 2654 if (auto od = d.isOverDeclaration()) 2655 { 2656 if (od.hasOverloads) 2657 { 2658 /* The scope is needed here to check whether a function in 2659 an overload set was added by means of a private alias (or a 2660 selective import). If the scope where the alias is created 2661 is imported somewhere, the overload set is visible, but the private 2662 alias is not. 2663 */ 2664 if (sc) 2665 { 2666 if (checkSymbolAccess(sc, od)) 2667 { 2668 if (int r = overloadApply(od.aliassym, dg, sc)) 2669 return r; 2670 } 2671 } 2672 else if (int r = overloadApply(od.aliassym, dg, sc)) 2673 return r; 2674 } 2675 else 2676 { 2677 if (int r = dg(od.aliassym)) 2678 return r; 2679 } 2680 next = od.overnext; 2681 } 2682 else if (auto fa = d.isFuncAliasDeclaration()) 2683 { 2684 if (fa.hasOverloads) 2685 { 2686 if (int r = overloadApply(fa.funcalias, dg, sc)) 2687 return r; 2688 } 2689 else if (auto fd = fa.toAliasFunc()) 2690 { 2691 if (int r = dg(fd)) 2692 return r; 2693 } 2694 else 2695 { 2696 d.error("is aliased to a function"); 2697 break; 2698 } 2699 next = fa.overnext; 2700 } 2701 else if (auto ad = d.isAliasDeclaration()) 2702 { 2703 if (sc) 2704 { 2705 if (checkSymbolAccess(sc, ad)) 2706 next = ad.toAlias(); 2707 } 2708 else 2709 next = ad.toAlias(); 2710 if (next == ad) 2711 break; 2712 if (next == fstart) 2713 break; 2714 } 2715 else if (auto td = d.isTemplateDeclaration()) 2716 { 2717 if (int r = dg(td)) 2718 return r; 2719 next = td.overnext; 2720 } 2721 else if (auto fd = d.isFuncDeclaration()) 2722 { 2723 if (int r = dg(fd)) 2724 return r; 2725 next = fd.overnext; 2726 } 2727 else if (auto os = d.isOverloadSet()) 2728 { 2729 foreach (ds; os.a) 2730 if (int r = dg(ds)) 2731 return r; 2732 } 2733 else 2734 { 2735 d.error("is aliased to a function"); 2736 break; 2737 // BUG: should print error message? 2738 } 2739 } 2740 return 0; 2741 } 2742 2743 /** 2744 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the 2745 mismatching modifiers to `buf`. 2746 2747 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e. 2748 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared". 2749 2750 Params: 2751 buf = output buffer to write to 2752 lhsMod = modifier on the left-hand side 2753 lhsMod = modifier on the right-hand side 2754 2755 Returns: 2756 2757 A tuple with `isMutable` and `isNotShared` set 2758 if the `lhsMod` is missing those modifiers (compared to rhs). 2759 */ 2760 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod) 2761 { 2762 static struct Mismatches 2763 { 2764 bool isNotShared; 2765 bool isMutable; 2766 } 2767 2768 Mismatches mismatches; 2769 2770 bool bothMutable = ((lhsMod & rhsMod) == 0); 2771 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0; 2772 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_); 2773 2774 if (lhsMod & MODFlags.shared_) 2775 buf.writestring("`shared` "); 2776 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_)) 2777 { 2778 buf.writestring("non-shared "); 2779 mismatches.isNotShared = true; 2780 } 2781 2782 if (bothMutable && sharedMismatchOnly) 2783 { 2784 } 2785 else if (lhsMod & MODFlags.immutable_) 2786 buf.writestring("`immutable` "); 2787 else if (lhsMod & MODFlags.const_) 2788 buf.writestring("`const` "); 2789 else if (lhsMod & MODFlags.wild) 2790 buf.writestring("`inout` "); 2791 else 2792 { 2793 buf.writestring("mutable "); 2794 mismatches.isMutable = true; 2795 } 2796 2797 return mismatches; 2798 } 2799 2800 /// 2801 unittest 2802 { 2803 OutBuffer buf; 2804 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0); 2805 assert(buf[] == "`shared` "); 2806 assert(!mismatches.isNotShared); 2807 2808 buf.setsize(0); 2809 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_); 2810 assert(buf[] == "non-shared "); 2811 assert(mismatches.isNotShared); 2812 2813 buf.setsize(0); 2814 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0); 2815 assert(buf[] == "`const` "); 2816 assert(!mismatches.isMutable); 2817 2818 buf.setsize(0); 2819 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_); 2820 assert(buf[] == "mutable "); 2821 assert(mismatches.isMutable); 2822 } 2823 2824 private const(char)* prependSpace(const(char)* str) 2825 { 2826 if (!str || !*str) return ""; 2827 2828 return (" " ~ str.toDString() ~ "\0").ptr; 2829 } 2830 2831 /// Flag used by $(LREF resolveFuncCall). 2832 enum FuncResolveFlag : ubyte 2833 { 2834 standard = 0, /// issue error messages, solve the call. 2835 quiet = 1, /// do not issue error message on no match, just return `null`. 2836 overloadOnly = 2, /// only resolve overloads. 2837 } 2838 2839 /******************************************* 2840 * Given a symbol that could be either a FuncDeclaration or 2841 * a function template, resolve it to a function symbol. 2842 * Params: 2843 * loc = instantiation location 2844 * sc = instantiation scope 2845 * s = instantiation symbol 2846 * tiargs = initial list of template arguments 2847 * tthis = if !NULL, the `this` argument type 2848 * fargs = arguments to function 2849 * flags = see $(LREF FuncResolveFlag). 2850 * Returns: 2851 * if match is found, then function symbol, else null 2852 */ 2853 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, 2854 Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags) 2855 { 2856 if (!s) 2857 return null; // no match 2858 2859 version (none) 2860 { 2861 printf("resolveFuncCall('%s')\n", s.toChars()); 2862 if (tthis) 2863 printf("\tthis: %s\n", tthis.toChars()); 2864 if (fargs) 2865 { 2866 for (size_t i = 0; i < fargs.dim; i++) 2867 { 2868 Expression arg = (*fargs)[i]; 2869 assert(arg.type); 2870 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars()); 2871 } 2872 } 2873 } 2874 2875 if (tiargs && arrayObjectIsError(tiargs) || 2876 fargs && arrayObjectIsError(cast(Objects*)fargs)) 2877 { 2878 return null; 2879 } 2880 2881 MatchAccumulator m; 2882 functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null); 2883 auto orig_s = s; 2884 2885 if (m.last > MATCH.nomatch && m.lastf) 2886 { 2887 if (m.count == 1) // exactly one match 2888 { 2889 if (!(flags & FuncResolveFlag.quiet)) 2890 m.lastf.functionSemantic(); 2891 return m.lastf; 2892 } 2893 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) 2894 { 2895 return m.lastf; 2896 } 2897 } 2898 2899 /* Failed to find a best match. 2900 * Do nothing or print error. 2901 */ 2902 if (m.last <= MATCH.nomatch) 2903 { 2904 // error was caused on matched function, not on the matching itself, 2905 // so return the function to produce a better diagnostic 2906 if (m.count == 1) 2907 return m.lastf; 2908 } 2909 2910 // We are done at this point, as the rest of this function generate 2911 // a diagnostic on invalid match 2912 if (flags & FuncResolveFlag.quiet) 2913 return null; 2914 2915 auto fd = s.isFuncDeclaration(); 2916 auto od = s.isOverDeclaration(); 2917 auto td = s.isTemplateDeclaration(); 2918 if (td && td.funcroot) 2919 s = fd = td.funcroot; 2920 2921 OutBuffer tiargsBuf; 2922 arrayObjectsToBuffer(&tiargsBuf, tiargs); 2923 2924 OutBuffer fargsBuf; 2925 fargsBuf.writeByte('('); 2926 argExpTypesToCBuffer(&fargsBuf, fargs); 2927 fargsBuf.writeByte(')'); 2928 if (tthis) 2929 tthis.modToBuffer(&fargsBuf); 2930 2931 // The call is ambiguous 2932 if (m.lastf && m.nextf) 2933 { 2934 TypeFunction tf1 = m.lastf.type.toTypeFunction(); 2935 TypeFunction tf2 = m.nextf.type.toTypeFunction(); 2936 const(char)* lastprms = parametersTypeToChars(tf1.parameterList); 2937 const(char)* nextprms = parametersTypeToChars(tf2.parameterList); 2938 2939 const(char)* mod1 = prependSpace(MODtoChars(tf1.mod)); 2940 const(char)* mod2 = prependSpace(MODtoChars(tf2.mod)); 2941 2942 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", 2943 s.parent.toPrettyChars(), s.ident.toChars(), 2944 fargsBuf.peekChars(), 2945 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1, 2946 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2); 2947 return null; 2948 } 2949 2950 // no match, generate an error messages 2951 if (!fd) 2952 { 2953 // all of overloads are templates 2954 if (td) 2955 { 2956 .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`, candidates are:", 2957 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), 2958 tiargsBuf.peekChars(), fargsBuf.peekChars()); 2959 2960 printCandidates(loc, td, sc.isDeprecated()); 2961 return null; 2962 } 2963 /* This case used to happen when several ctors are mixed in an agregate. 2964 A (bad) error message is already generated in overloadApply(). 2965 see https://issues.dlang.org/show_bug.cgi?id=19729 2966 and https://issues.dlang.org/show_bug.cgi?id=17259 2967 */ 2968 if (!od) 2969 return null; 2970 } 2971 2972 if (od) 2973 { 2974 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`", 2975 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); 2976 return null; 2977 } 2978 2979 // remove when deprecation period of class allocators and deallocators is over 2980 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc)) 2981 return null; 2982 2983 bool hasOverloads = fd.overnext !is null; 2984 auto tf = fd.type.toTypeFunction(); 2985 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch 2986 { 2987 OutBuffer thisBuf, funcBuf; 2988 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 2989 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 2990 if (hasOverloads) 2991 { 2992 .error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:", 2993 fd.ident.toChars(), thisBuf.peekChars()); 2994 printCandidates(loc, fd, sc.isDeprecated()); 2995 return null; 2996 } 2997 2998 const(char)* failMessage; 2999 functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); 3000 if (failMessage) 3001 { 3002 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", 3003 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), 3004 tf.modToChars(), fargsBuf.peekChars()); 3005 errorSupplemental(loc, failMessage); 3006 return null; 3007 } 3008 3009 auto fullFdPretty = fd.toPrettyChars(); 3010 .error(loc, "%smethod `%s` is not callable using a %sobject", 3011 funcBuf.peekChars(), fullFdPretty, thisBuf.peekChars()); 3012 3013 if (mismatches.isNotShared) 3014 .errorSupplemental(loc, "Consider adding `shared` to %s", fullFdPretty); 3015 else if (mismatches.isMutable) 3016 .errorSupplemental(loc, "Consider adding `const` or `inout` to %s", fullFdPretty); 3017 return null; 3018 } 3019 3020 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco); 3021 if (hasOverloads) 3022 { 3023 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:", 3024 fd.toChars(), fargsBuf.peekChars()); 3025 printCandidates(loc, fd, sc.isDeprecated()); 3026 return null; 3027 } 3028 3029 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", 3030 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), 3031 tf.modToChars(), fargsBuf.peekChars()); 3032 // re-resolve to check for supplemental message 3033 const(char)* failMessage; 3034 functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); 3035 if (failMessage) 3036 errorSupplemental(loc, failMessage); 3037 return null; 3038 } 3039 3040 /******************************************* 3041 * Prints template and function overload candidates as supplemental errors. 3042 * Params: 3043 * loc = instantiation location 3044 * declaration = the declaration to print overload candidates for 3045 * showDeprecated = If `false`, `deprecated` function won't be shown 3046 */ 3047 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated) 3048 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) 3049 { 3050 // max num of overloads to print (-v overrides this). 3051 enum int DisplayLimit = 5; 3052 int displayed; 3053 const(char)* constraintsTip; 3054 3055 overloadApply(declaration, (Dsymbol s) 3056 { 3057 Dsymbol nextOverload; 3058 3059 if (auto fd = s.isFuncDeclaration()) 3060 { 3061 // Don't print overloads which have errors. 3062 // Not that if the whole overload set has errors, we'll never reach 3063 // this point so there's no risk of printing no candidate 3064 if (fd.errors || fd.type.ty == Terror) 3065 return 0; 3066 // Don't print disabled functions, or `deprecated` outside of deprecated scope 3067 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated)) 3068 return 0; 3069 3070 auto tf = cast(TypeFunction) fd.type; 3071 .errorSupplemental(fd.loc, "`%s%s`", fd.toPrettyChars(), 3072 parametersTypeToChars(tf.parameterList)); 3073 nextOverload = fd.overnext; 3074 } 3075 else if (auto td = s.isTemplateDeclaration()) 3076 { 3077 import dmd.staticcond; 3078 3079 const tmsg = td.toCharsNoConstraints(); 3080 const cmsg = td.getConstraintEvalError(constraintsTip); 3081 if (cmsg) 3082 .errorSupplemental(td.loc, "`%s`\n%s", tmsg, cmsg); 3083 else 3084 .errorSupplemental(td.loc, "`%s`", tmsg); 3085 nextOverload = td.overnext; 3086 } 3087 3088 if (global.params.verbose || ++displayed < DisplayLimit) 3089 return 0; 3090 3091 // Too many overloads to sensibly display. 3092 // Just show count of remaining overloads. 3093 int num = 0; 3094 overloadApply(nextOverload, (s) { ++num; return 0; }); 3095 3096 if (num > 0) 3097 .errorSupplemental(loc, "... (%d more, -v to show) ...", num); 3098 return 1; // stop iterating 3099 }); 3100 3101 // Nothing was displayed, all overloads are either disabled or deprecated 3102 if (!displayed) 3103 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`"); 3104 // should be only in verbose mode 3105 if (constraintsTip) 3106 .tip(constraintsTip); 3107 } 3108 3109 /************************************** 3110 * Returns an indirect type one step from t. 3111 */ 3112 Type getIndirection(Type t) 3113 { 3114 t = t.baseElemOf(); 3115 if (t.ty == Tarray || t.ty == Tpointer) 3116 return t.nextOf().toBasetype(); 3117 if (t.ty == Taarray || t.ty == Tclass) 3118 return t; 3119 if (t.ty == Tstruct) 3120 return t.hasPointers() ? t : null; // TODO 3121 3122 // should consider TypeDelegate? 3123 return null; 3124 } 3125 3126 /************************************** 3127 * Performs type-based alias analysis between a newly created value and a pre- 3128 * existing memory reference: 3129 * 3130 * Assuming that a reference A to a value of type `ta` was available to the code 3131 * that created a reference B to a value of type `tb`, it returns whether B 3132 * might alias memory reachable from A based on the types involved (either 3133 * directly or via any number of indirections in either A or B). 3134 * 3135 * This relation is not symmetric in the two arguments. For example, a 3136 * a `const(int)` reference can point to a pre-existing `int`, but not the other 3137 * way round. 3138 * 3139 * Examples: 3140 * 3141 * ta, tb, result 3142 * `const(int)`, `int`, `false` 3143 * `int`, `const(int)`, `true` 3144 * `int`, `immutable(int)`, `false` 3145 * const(immutable(int)*), immutable(int)*, false // BUG: returns true 3146 * 3147 * Params: 3148 * ta = value type being referred to 3149 * tb = referred to value type that could be constructed from ta 3150 * 3151 * Returns: 3152 * true if reference to `tb` is isolated from reference to `ta` 3153 */ 3154 private bool traverseIndirections(Type ta, Type tb) 3155 { 3156 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars()); 3157 3158 /* Threaded list of aggregate types already examined, 3159 * used to break cycles. 3160 * Cycles in type graphs can only occur with aggregates. 3161 */ 3162 static struct Ctxt 3163 { 3164 Ctxt* prev; 3165 Type type; // an aggregate type 3166 } 3167 3168 static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass) 3169 { 3170 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); 3171 ta = ta.baseElemOf(); 3172 tb = tb.baseElemOf(); 3173 3174 // First, check if the pointed-to types are convertible to each other such 3175 // that they might alias directly. 3176 static bool mayAliasDirect(Type source, Type target) 3177 { 3178 return 3179 // if source is the same as target or can be const-converted to target 3180 source.constConv(target) != MATCH.nomatch || 3181 // if target is void and source can be const-converted to target 3182 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)); 3183 } 3184 3185 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb)) 3186 { 3187 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); 3188 return false; 3189 } 3190 if (ta.nextOf() && ta.nextOf() == tb.nextOf()) 3191 { 3192 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); 3193 return true; 3194 } 3195 3196 if (tb.ty == Tclass || tb.ty == Tstruct) 3197 { 3198 for (Ctxt* c = ctxt; c; c = c.prev) 3199 if (tb == c.type) 3200 return true; 3201 Ctxt c; 3202 c.prev = ctxt; 3203 c.type = tb; 3204 3205 /* Traverse the type of each field of the aggregate 3206 */ 3207 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); 3208 foreach (v; sym.fields) 3209 { 3210 Type tprmi = v.type.addMod(tb.mod); 3211 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars()); 3212 if (!traverse(ta, tprmi, &c, reversePass)) 3213 return false; 3214 } 3215 } 3216 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) 3217 { 3218 Type tind = tb.nextOf(); 3219 if (!traverse(ta, tind, ctxt, reversePass)) 3220 return false; 3221 } 3222 else if (tb.hasPointers()) 3223 { 3224 // BUG: consider the context pointer of delegate types 3225 return false; 3226 } 3227 3228 // Still no match, so try breaking up ta if we have not done so yet. 3229 if (!reversePass) 3230 return traverse(tb, ta, ctxt, true); 3231 3232 return true; 3233 } 3234 3235 // To handle arbitrary levels of indirections in both parameters, we 3236 // recursively descend into aggregate members/levels of indirection in both 3237 // `ta` and `tb` while avoiding cycles. Start with the original types. 3238 const result = traverse(ta, tb, null, false); 3239 //printf(" returns %d\n", result); 3240 return result; 3241 } 3242 3243 /* For all functions between outerFunc and f, mark them as needing 3244 * a closure. 3245 */ 3246 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc) 3247 { 3248 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc)) 3249 { 3250 FuncDeclaration fy = sx.isFuncDeclaration(); 3251 if (fy && fy.closureVars.dim) 3252 { 3253 /* fy needs a closure if it has closureVars[], 3254 * because the frame pointer in the closure will be accessed. 3255 */ 3256 fy.requiresClosure = true; 3257 } 3258 } 3259 } 3260 3261 /******** 3262 * Given a nested function f inside a function outerFunc, check 3263 * if any sibling callers of f have escaped. If so, mark 3264 * all the enclosing functions as needing closures. 3265 * This is recursive: we need to check the callers of our siblings. 3266 * Note that nested functions can only call lexically earlier nested 3267 * functions, so loops are impossible. 3268 * Params: 3269 * f = inner function (nested within outerFunc) 3270 * outerFunc = outer function 3271 * p = for internal recursion use 3272 * Returns: 3273 * true if any closures were needed 3274 */ 3275 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null) 3276 { 3277 static struct PrevSibling 3278 { 3279 PrevSibling* p; 3280 FuncDeclaration f; 3281 } 3282 3283 PrevSibling ps; 3284 ps.p = cast(PrevSibling*)p; 3285 ps.f = f; 3286 3287 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars()); 3288 bool bAnyClosures = false; 3289 for (size_t i = 0; i < f.siblingCallers.dim; ++i) 3290 { 3291 FuncDeclaration g = f.siblingCallers[i]; 3292 if (g.isThis() || g.tookAddressOf) 3293 { 3294 markAsNeedingClosure(g, outerFunc); 3295 bAnyClosures = true; 3296 } 3297 3298 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc)) 3299 { 3300 // A parent of the sibling had its address taken. 3301 // Assume escaping of parent affects its children, so needs propagating. 3302 // see https://issues.dlang.org/show_bug.cgi?id=19679 3303 FuncDeclaration parentFunc = parent.isFuncDeclaration; 3304 if (parentFunc && parentFunc.tookAddressOf) 3305 { 3306 markAsNeedingClosure(parentFunc, outerFunc); 3307 bAnyClosures = true; 3308 } 3309 } 3310 3311 PrevSibling* prev = cast(PrevSibling*)p; 3312 while (1) 3313 { 3314 if (!prev) 3315 { 3316 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps); 3317 break; 3318 } 3319 if (prev.f == g) 3320 break; 3321 prev = prev.p; 3322 } 3323 } 3324 //printf("\t%d\n", bAnyClosures); 3325 return bAnyClosures; 3326 } 3327 3328 /*********************************************************** 3329 * Used as a way to import a set of functions from another scope into this one. 3330 */ 3331 extern (C++) final class FuncAliasDeclaration : FuncDeclaration 3332 { 3333 FuncDeclaration funcalias; 3334 bool hasOverloads; 3335 3336 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true) 3337 { 3338 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type); 3339 assert(funcalias != this); 3340 this.funcalias = funcalias; 3341 3342 this.hasOverloads = hasOverloads; 3343 if (hasOverloads) 3344 { 3345 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration()) 3346 this.hasOverloads = fad.hasOverloads; 3347 } 3348 else 3349 { 3350 // for internal use 3351 assert(!funcalias.isFuncAliasDeclaration()); 3352 this.hasOverloads = false; 3353 } 3354 userAttribDecl = funcalias.userAttribDecl; 3355 } 3356 3357 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout 3358 { 3359 return this; 3360 } 3361 3362 override const(char)* kind() const 3363 { 3364 return "function alias"; 3365 } 3366 3367 override inout(FuncDeclaration) toAliasFunc() inout 3368 { 3369 return funcalias.toAliasFunc(); 3370 } 3371 3372 override void accept(Visitor v) 3373 { 3374 v.visit(this); 3375 } 3376 } 3377 3378 /*********************************************************** 3379 */ 3380 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration 3381 { 3382 TOK tok; // TOK.function_ or TOK.delegate_ 3383 Type treq; // target of return type inference 3384 3385 // backend 3386 bool deferToObj; 3387 3388 extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) 3389 { 3390 super(loc, endloc, null, STC.undefined_, type); 3391 this.ident = id ? id : Id.empty; 3392 this.tok = tok; 3393 this.fes = fes; 3394 // Always infer scope for function literals 3395 // See https://issues.dlang.org/show_bug.cgi?id=20362 3396 this.flags |= FUNCFLAG.inferScope; 3397 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars()); 3398 } 3399 3400 override Dsymbol syntaxCopy(Dsymbol s) 3401 { 3402 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); 3403 assert(!s); 3404 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); 3405 f.treq = treq; // don't need to copy 3406 return FuncDeclaration.syntaxCopy(f); 3407 } 3408 3409 override bool isNested() const 3410 { 3411 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); 3412 return (tok != TOK.function_) && !isThis(); 3413 } 3414 3415 override inout(AggregateDeclaration) isThis() inout 3416 { 3417 return tok == TOK.delegate_ ? super.isThis() : null; 3418 } 3419 3420 override bool isVirtual() const 3421 { 3422 return false; 3423 } 3424 3425 override bool addPreInvariant() 3426 { 3427 return false; 3428 } 3429 3430 override bool addPostInvariant() 3431 { 3432 return false; 3433 } 3434 3435 /******************************* 3436 * Modify all expression type of return statements to tret. 3437 * 3438 * On function literals, return type may be modified based on the context type 3439 * after its semantic3 is done, in FuncExp::implicitCastTo. 3440 * 3441 * A function() dg = (){ return new B(); } // OK if is(B : A) == true 3442 * 3443 * If B to A conversion is convariant that requires offseet adjusting, 3444 * all return statements should be adjusted to return expressions typed A. 3445 */ 3446 void modifyReturns(Scope* sc, Type tret) 3447 { 3448 import dmd.statement_rewrite_walker; 3449 3450 extern (C++) final class RetWalker : StatementRewriteWalker 3451 { 3452 alias visit = typeof(super).visit; 3453 public: 3454 Scope* sc; 3455 Type tret; 3456 FuncLiteralDeclaration fld; 3457 3458 override void visit(ReturnStatement s) 3459 { 3460 Expression exp = s.exp; 3461 if (exp && !exp.type.equals(tret)) 3462 { 3463 s.exp = exp.castTo(sc, tret); 3464 } 3465 } 3466 } 3467 3468 if (semanticRun < PASS.semantic3done) 3469 return; 3470 3471 if (fes) 3472 return; 3473 3474 scope RetWalker w = new RetWalker(); 3475 w.sc = sc; 3476 w.tret = tret; 3477 w.fld = this; 3478 fbody.accept(w); 3479 3480 // Also update the inferred function type to match the new return type. 3481 // This is required so the code generator does not try to cast the 3482 // modified returns back to the original type. 3483 if (inferRetType && type.nextOf() != tret) 3484 type.toTypeFunction().next = tret; 3485 } 3486 3487 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout 3488 { 3489 return this; 3490 } 3491 3492 override const(char)* kind() const 3493 { 3494 // GCC requires the (char*) casts 3495 return (tok != TOK.function_) ? "delegate" : "function"; 3496 } 3497 3498 override const(char)* toPrettyChars(bool QualifyTypes = false) 3499 { 3500 if (parent) 3501 { 3502 TemplateInstance ti = parent.isTemplateInstance(); 3503 if (ti) 3504 return ti.tempdecl.toPrettyChars(QualifyTypes); 3505 } 3506 return Dsymbol.toPrettyChars(QualifyTypes); 3507 } 3508 3509 override void accept(Visitor v) 3510 { 3511 v.visit(this); 3512 } 3513 } 3514 3515 /*********************************************************** 3516 */ 3517 extern (C++) final class CtorDeclaration : FuncDeclaration 3518 { 3519 bool isCpCtor; 3520 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false) 3521 { 3522 super(loc, endloc, Id.ctor, stc, type); 3523 this.isCpCtor = isCpCtor; 3524 //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); 3525 } 3526 3527 override Dsymbol syntaxCopy(Dsymbol s) 3528 { 3529 assert(!s); 3530 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy()); 3531 return FuncDeclaration.syntaxCopy(f); 3532 } 3533 3534 override const(char)* kind() const 3535 { 3536 return isCpCtor ? "copy constructor" : "constructor"; 3537 } 3538 3539 override const(char)* toChars() const 3540 { 3541 return "this"; 3542 } 3543 3544 override bool isVirtual() const 3545 { 3546 return false; 3547 } 3548 3549 override bool addPreInvariant() 3550 { 3551 return false; 3552 } 3553 3554 override bool addPostInvariant() 3555 { 3556 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); 3557 } 3558 3559 override inout(CtorDeclaration) isCtorDeclaration() inout 3560 { 3561 return this; 3562 } 3563 3564 override void accept(Visitor v) 3565 { 3566 v.visit(this); 3567 } 3568 } 3569 3570 /*********************************************************** 3571 */ 3572 extern (C++) final class PostBlitDeclaration : FuncDeclaration 3573 { 3574 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) 3575 { 3576 super(loc, endloc, id, stc, null); 3577 } 3578 3579 override Dsymbol syntaxCopy(Dsymbol s) 3580 { 3581 assert(!s); 3582 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident); 3583 return FuncDeclaration.syntaxCopy(dd); 3584 } 3585 3586 override bool isVirtual() const 3587 { 3588 return false; 3589 } 3590 3591 override bool addPreInvariant() 3592 { 3593 return false; 3594 } 3595 3596 override bool addPostInvariant() 3597 { 3598 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); 3599 } 3600 3601 override bool overloadInsert(Dsymbol s) 3602 { 3603 return false; // cannot overload postblits 3604 } 3605 3606 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout 3607 { 3608 return this; 3609 } 3610 3611 override void accept(Visitor v) 3612 { 3613 v.visit(this); 3614 } 3615 } 3616 3617 /*********************************************************** 3618 */ 3619 extern (C++) final class DtorDeclaration : FuncDeclaration 3620 { 3621 extern (D) this(const ref Loc loc, const ref Loc endloc) 3622 { 3623 super(loc, endloc, Id.dtor, STC.undefined_, null); 3624 } 3625 3626 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) 3627 { 3628 super(loc, endloc, id, stc, null); 3629 } 3630 3631 override Dsymbol syntaxCopy(Dsymbol s) 3632 { 3633 assert(!s); 3634 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident); 3635 return FuncDeclaration.syntaxCopy(dd); 3636 } 3637 3638 override const(char)* kind() const 3639 { 3640 return "destructor"; 3641 } 3642 3643 override const(char)* toChars() const 3644 { 3645 return "~this"; 3646 } 3647 3648 override bool isVirtual() const 3649 { 3650 // D dtor's don't get put into the vtbl[] 3651 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable 3652 return vtblIndex != -1; 3653 } 3654 3655 override bool addPreInvariant() 3656 { 3657 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); 3658 } 3659 3660 override bool addPostInvariant() 3661 { 3662 return false; 3663 } 3664 3665 override bool overloadInsert(Dsymbol s) 3666 { 3667 return false; // cannot overload destructors 3668 } 3669 3670 override inout(DtorDeclaration) isDtorDeclaration() inout 3671 { 3672 return this; 3673 } 3674 3675 override void accept(Visitor v) 3676 { 3677 v.visit(this); 3678 } 3679 } 3680 3681 /*********************************************************** 3682 */ 3683 extern (C++) class StaticCtorDeclaration : FuncDeclaration 3684 { 3685 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) 3686 { 3687 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null); 3688 } 3689 3690 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) 3691 { 3692 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); 3693 } 3694 3695 override Dsymbol syntaxCopy(Dsymbol s) 3696 { 3697 assert(!s); 3698 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class); 3699 return FuncDeclaration.syntaxCopy(scd); 3700 } 3701 3702 override final inout(AggregateDeclaration) isThis() inout 3703 { 3704 return null; 3705 } 3706 3707 override final bool isVirtual() const 3708 { 3709 return false; 3710 } 3711 3712 override final bool addPreInvariant() 3713 { 3714 return false; 3715 } 3716 3717 override final bool addPostInvariant() 3718 { 3719 return false; 3720 } 3721 3722 override final bool hasStaticCtorOrDtor() 3723 { 3724 return true; 3725 } 3726 3727 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout 3728 { 3729 return this; 3730 } 3731 3732 override void accept(Visitor v) 3733 { 3734 v.visit(this); 3735 } 3736 } 3737 3738 /*********************************************************** 3739 */ 3740 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration 3741 { 3742 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) 3743 { 3744 super(loc, endloc, "_sharedStaticCtor", stc); 3745 } 3746 3747 override Dsymbol syntaxCopy(Dsymbol s) 3748 { 3749 assert(!s); 3750 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class); 3751 return FuncDeclaration.syntaxCopy(scd); 3752 } 3753 3754 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout 3755 { 3756 return this; 3757 } 3758 3759 override void accept(Visitor v) 3760 { 3761 v.visit(this); 3762 } 3763 } 3764 3765 /*********************************************************** 3766 */ 3767 extern (C++) class StaticDtorDeclaration : FuncDeclaration 3768 { 3769 VarDeclaration vgate; // 'gate' variable 3770 3771 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) 3772 { 3773 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null); 3774 } 3775 3776 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) 3777 { 3778 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); 3779 } 3780 3781 override Dsymbol syntaxCopy(Dsymbol s) 3782 { 3783 assert(!s); 3784 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class); 3785 return FuncDeclaration.syntaxCopy(sdd); 3786 } 3787 3788 override final inout(AggregateDeclaration) isThis() inout 3789 { 3790 return null; 3791 } 3792 3793 override final bool isVirtual() const 3794 { 3795 return false; 3796 } 3797 3798 override final bool hasStaticCtorOrDtor() 3799 { 3800 return true; 3801 } 3802 3803 override final bool addPreInvariant() 3804 { 3805 return false; 3806 } 3807 3808 override final bool addPostInvariant() 3809 { 3810 return false; 3811 } 3812 3813 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout 3814 { 3815 return this; 3816 } 3817 3818 override void accept(Visitor v) 3819 { 3820 v.visit(this); 3821 } 3822 } 3823 3824 /*********************************************************** 3825 */ 3826 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration 3827 { 3828 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) 3829 { 3830 super(loc, endloc, "_sharedStaticDtor", stc); 3831 } 3832 3833 override Dsymbol syntaxCopy(Dsymbol s) 3834 { 3835 assert(!s); 3836 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class); 3837 return FuncDeclaration.syntaxCopy(sdd); 3838 } 3839 3840 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout 3841 { 3842 return this; 3843 } 3844 3845 override void accept(Visitor v) 3846 { 3847 v.visit(this); 3848 } 3849 } 3850 3851 /*********************************************************** 3852 */ 3853 extern (C++) final class InvariantDeclaration : FuncDeclaration 3854 { 3855 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) 3856 { 3857 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); 3858 this.fbody = fbody; 3859 } 3860 3861 override Dsymbol syntaxCopy(Dsymbol s) 3862 { 3863 assert(!s); 3864 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null); 3865 return FuncDeclaration.syntaxCopy(id); 3866 } 3867 3868 override bool isVirtual() const 3869 { 3870 return false; 3871 } 3872 3873 override bool addPreInvariant() 3874 { 3875 return false; 3876 } 3877 3878 override bool addPostInvariant() 3879 { 3880 return false; 3881 } 3882 3883 override inout(InvariantDeclaration) isInvariantDeclaration() inout 3884 { 3885 return this; 3886 } 3887 3888 override void accept(Visitor v) 3889 { 3890 v.visit(this); 3891 } 3892 } 3893 3894 3895 /*********************************************************** 3896 */ 3897 extern (C++) final class UnitTestDeclaration : FuncDeclaration 3898 { 3899 char* codedoc; // for documented unittest 3900 3901 // toObjFile() these nested functions after this one 3902 FuncDeclarations deferredNested; 3903 3904 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc) 3905 { 3906 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null); 3907 this.codedoc = codedoc; 3908 } 3909 3910 override Dsymbol syntaxCopy(Dsymbol s) 3911 { 3912 assert(!s); 3913 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); 3914 return FuncDeclaration.syntaxCopy(utd); 3915 } 3916 3917 override inout(AggregateDeclaration) isThis() inout 3918 { 3919 return null; 3920 } 3921 3922 override bool isVirtual() const 3923 { 3924 return false; 3925 } 3926 3927 override bool addPreInvariant() 3928 { 3929 return false; 3930 } 3931 3932 override bool addPostInvariant() 3933 { 3934 return false; 3935 } 3936 3937 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout 3938 { 3939 return this; 3940 } 3941 3942 override void accept(Visitor v) 3943 { 3944 v.visit(this); 3945 } 3946 } 3947 3948 /*********************************************************** 3949 */ 3950 extern (C++) final class NewDeclaration : FuncDeclaration 3951 { 3952 ParameterList parameterList; 3953 3954 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, ref ParameterList parameterList) 3955 { 3956 super(loc, endloc, Id.classNew, STC.static_ | stc, null); 3957 this.parameterList = parameterList; 3958 } 3959 3960 override Dsymbol syntaxCopy(Dsymbol s) 3961 { 3962 assert(!s); 3963 auto parameterList = parameterList.syntaxCopy(); 3964 auto f = new NewDeclaration(loc, endloc, storage_class, parameterList); 3965 return FuncDeclaration.syntaxCopy(f); 3966 } 3967 3968 override const(char)* kind() const 3969 { 3970 return "allocator"; 3971 } 3972 3973 override bool isVirtual() const 3974 { 3975 return false; 3976 } 3977 3978 override bool addPreInvariant() 3979 { 3980 return false; 3981 } 3982 3983 override bool addPostInvariant() 3984 { 3985 return false; 3986 } 3987 3988 override inout(NewDeclaration) isNewDeclaration() inout 3989 { 3990 return this; 3991 } 3992 3993 override void accept(Visitor v) 3994 { 3995 v.visit(this); 3996 } 3997 }