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