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