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