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