1 /** 2 * A scope as defined by curly braces `{}`. 3 * 4 * Not to be confused with the `scope` storage class. 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) 10 * Documentation: https://dlang.org/phobos/dmd_dscope.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d 12 */ 13 14 module dmd.dscope; 15 16 import core.stdc.stdio; 17 import core.stdc.string; 18 import dmd.aggregate; 19 import dmd.arraytypes; 20 import dmd.astenums; 21 import dmd.attrib; 22 import dmd.ctorflow; 23 import dmd.dclass; 24 import dmd.declaration; 25 import dmd.dmodule; 26 import dmd.doc; 27 import dmd.dsymbol; 28 import dmd.dsymbolsem; 29 import dmd.dtemplate; 30 import dmd.expression; 31 import dmd.errors; 32 import dmd.func; 33 import dmd.globals; 34 import dmd.id; 35 import dmd.identifier; 36 import dmd.location; 37 import dmd.common.outbuffer; 38 import dmd.root.rmem; 39 import dmd.root.speller; 40 import dmd.statement; 41 import dmd.target; 42 import dmd.tokens; 43 44 //version=LOGSEARCH; 45 46 47 // List of flags that can be applied to this `Scope` 48 enum SCOPE 49 { 50 ctor = 0x0001, /// constructor type 51 noaccesscheck = 0x0002, /// don't do access checks 52 condition = 0x0004, /// inside static if/assert condition 53 debug_ = 0x0008, /// inside debug conditional 54 constraint = 0x0010, /// inside template constraint 55 invariant_ = 0x0020, /// inside invariant code 56 require = 0x0040, /// inside in contract code 57 ensure = 0x0060, /// inside out contract code 58 contract = 0x0060, /// [mask] we're inside contract code 59 ctfe = 0x0080, /// inside a ctfe-only expression 60 compile = 0x0100, /// inside __traits(compile) 61 ignoresymbolvisibility = 0x0200, /// ignore symbol visibility 62 /// https://issues.dlang.org/show_bug.cgi?id=15907 63 Cfile = 0x0800, /// C semantics apply 64 free = 0x8000, /// is on free list 65 66 fullinst = 0x10000, /// fully instantiate templates 67 ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block 68 } 69 70 /// Flags that are carried along with a scope push() 71 private enum PersistentFlags = 72 SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | 73 SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | 74 SCOPE.Cfile | SCOPE.ctfeBlock; 75 76 extern (C++) struct Scope 77 { 78 Scope* enclosing; /// enclosing Scope 79 80 Module _module; /// Root module 81 ScopeDsymbol scopesym; /// current symbol 82 FuncDeclaration func; /// function we are in 83 VarDeclaration varDecl; /// variable we are in during semantic2 84 Dsymbol parent; /// parent to use 85 LabelStatement slabel; /// enclosing labelled statement 86 SwitchStatement sw; /// enclosing switch statement 87 Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement 88 TryFinallyStatement tf; /// enclosing try finally statement 89 ScopeGuardStatement os; /// enclosing scope(xxx) statement 90 Statement sbreak; /// enclosing statement that supports "break" 91 Statement scontinue; /// enclosing statement that supports "continue" 92 ForeachStatement fes; /// if nested function for ForeachStatement, this is it 93 Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ 94 Dsymbol inunion; /// != null if processing members of a union 95 bool nofree; /// true if shouldn't free it 96 bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) 97 int intypeof; /// in typeof(exp) 98 VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init 99 100 /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope). 101 * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint). 102 * If minst && tinst, it's in instantiated code scope without speculation. 103 * If !minst && tinst, it's in instantiated code scope with speculation. 104 */ 105 Module minst; /// root module where the instantiated templates should belong to 106 TemplateInstance tinst; /// enclosing template instance 107 108 CtorFlow ctorflow; /// flow analysis for constructors 109 110 /// alignment for struct members 111 AlignDeclaration aligndecl; 112 113 /// C++ namespace this symbol is in 114 CPPNamespaceDeclaration namespace; 115 116 /// linkage for external functions 117 LINK linkage = LINK.d; 118 119 /// mangle type 120 CPPMANGLE cppmangle = CPPMANGLE.def; 121 122 /// inlining strategy for functions 123 PragmaDeclaration inlining; 124 125 /// visibility for class members 126 Visibility visibility = Visibility(Visibility.Kind.public_); 127 int explicitVisibility; /// set if in an explicit visibility attribute 128 129 StorageClass stc; /// storage class 130 131 DeprecatedDeclaration depdecl; /// customized deprecation message 132 133 uint flags; 134 135 // user defined attributes 136 UserAttributeDeclaration userAttribDecl; 137 138 DocComment* lastdc; /// documentation comment for last symbol at this scope 139 uint[void*] anchorCounts; /// lookup duplicate anchor name count 140 Identifier prevAnchor; /// qualified symbol name of last doc anchor 141 142 AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value, 143 /// do not set wasRead for it 144 145 extern (D) __gshared Scope* freelist; 146 147 extern (D) static Scope* alloc() 148 { 149 if (freelist) 150 { 151 Scope* s = freelist; 152 freelist = s.enclosing; 153 //printf("freelist %p\n", s); 154 assert(s.flags & SCOPE.free); 155 s.flags &= ~SCOPE.free; 156 return s; 157 } 158 return new Scope(); 159 } 160 161 extern (D) static Scope* createGlobal(Module _module) 162 { 163 Scope* sc = Scope.alloc(); 164 *sc = Scope.init; 165 sc._module = _module; 166 sc.minst = _module; 167 sc.scopesym = new ScopeDsymbol(); 168 sc.scopesym.symtab = new DsymbolTable(); 169 // Add top level package as member of this global scope 170 Dsymbol m = _module; 171 while (m.parent) 172 m = m.parent; 173 m.addMember(null, sc.scopesym); 174 m.parent = null; // got changed by addMember() 175 if (_module.filetype == FileType.c) 176 sc.flags |= SCOPE.Cfile; 177 // Create the module scope underneath the global scope 178 sc = sc.push(_module); 179 sc.parent = _module; 180 return sc; 181 } 182 183 extern (D) Scope* copy() 184 { 185 Scope* sc = Scope.alloc(); 186 *sc = this; 187 /* https://issues.dlang.org/show_bug.cgi?id=11777 188 * The copied scope should not inherit fieldinit. 189 */ 190 sc.ctorflow.fieldinit = null; 191 return sc; 192 } 193 194 extern (D) Scope* push() 195 { 196 Scope* s = copy(); 197 //printf("Scope::push(this = %p) new = %p\n", this, s); 198 assert(!(flags & SCOPE.free)); 199 s.scopesym = null; 200 s.enclosing = &this; 201 debug 202 { 203 if (enclosing) 204 assert(!(enclosing.flags & SCOPE.free)); 205 if (s == enclosing) 206 { 207 printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing); 208 } 209 assert(s != enclosing); 210 } 211 s.slabel = null; 212 s.nofree = false; 213 s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup; 214 s.flags = (flags & PersistentFlags); 215 s.lastdc = null; 216 assert(&this != s); 217 return s; 218 } 219 220 extern (D) Scope* push(ScopeDsymbol ss) 221 { 222 //printf("Scope::push(%s)\n", ss.toChars()); 223 Scope* s = push(); 224 s.scopesym = ss; 225 return s; 226 } 227 228 extern (D) Scope* pop() 229 { 230 //printf("Scope::pop() %p nofree = %d\n", this, nofree); 231 if (enclosing) 232 enclosing.ctorflow.OR(ctorflow); 233 ctorflow.freeFieldinit(); 234 235 Scope* enc = enclosing; 236 if (!nofree) 237 { 238 if (mem.isGCEnabled) 239 this = this.init; 240 enclosing = freelist; 241 freelist = &this; 242 flags |= SCOPE.free; 243 } 244 return enc; 245 } 246 247 /************************* 248 * Similar to pop(), but the results in `this` are not folded 249 * into `enclosing`. 250 */ 251 extern (D) void detach() 252 { 253 ctorflow.freeFieldinit(); 254 enclosing = null; 255 pop(); 256 } 257 258 extern (D) Scope* startCTFE() 259 { 260 Scope* sc = this.push(); 261 sc.flags = this.flags | SCOPE.ctfe; 262 version (none) 263 { 264 /* TODO: Currently this is not possible, because we need to 265 * unspeculative some types and symbols if they are necessary for the 266 * final executable. Consider: 267 * 268 * struct S(T) { 269 * string toString() const { return "instantiated"; } 270 * } 271 * enum x = S!int(); 272 * void main() { 273 * // To call x.toString in runtime, compiler should unspeculative S!int. 274 * assert(x.toString() == "instantiated"); 275 * } 276 * 277 * This results in an undefined reference to `RTInfoImpl`: 278 * class C { int a,b,c; int* p,q; } 279 * void test() { C c = new C(); } 280 */ 281 // If a template is instantiated from CT evaluated expression, 282 // compiler can elide its code generation. 283 sc.tinst = null; 284 sc.minst = null; 285 } 286 return sc; 287 } 288 289 extern (D) Scope* endCTFE() 290 { 291 assert(flags & SCOPE.ctfe); 292 return pop(); 293 } 294 295 296 /******************************* 297 * Merge results of `ctorflow` into `this`. 298 * Params: 299 * loc = for error messages 300 * ctorflow = flow results to merge in 301 */ 302 extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow) 303 { 304 if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper)) 305 error(loc, "one path skips constructor"); 306 307 const fies = ctorflow.fieldinit; 308 if (this.ctorflow.fieldinit.length && fies.length) 309 { 310 FuncDeclaration f = func; 311 if (fes) 312 f = fes.func; 313 auto ad = f.isMemberDecl(); 314 assert(ad); 315 foreach (i, v; ad.fields) 316 { 317 bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); 318 auto fieldInit = &this.ctorflow.fieldinit[i]; 319 const fiesCurrent = fies[i]; 320 if (fieldInit.loc is Loc.init) 321 fieldInit.loc = fiesCurrent.loc; 322 if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit) 323 { 324 error(loc, "one path skips field `%s`", v.toChars()); 325 } 326 } 327 } 328 } 329 330 /************************************ 331 * Perform unqualified name lookup by following the chain of scopes up 332 * until found. 333 * 334 * Params: 335 * loc = location to use for error messages 336 * ident = name to look up 337 * pscopesym = if supplied and name is found, set to scope that ident was found in 338 * flags = modify search based on flags 339 * 340 * Returns: 341 * symbol if found, null if not 342 */ 343 extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) 344 { 345 version (LOGSEARCH) 346 { 347 printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags); 348 // Print scope chain 349 for (Scope* sc = &this; sc; sc = sc.enclosing) 350 { 351 if (!sc.scopesym) 352 continue; 353 printf("\tscope %s\n", sc.scopesym.toChars()); 354 } 355 356 static void printMsg(string txt, Dsymbol s) 357 { 358 printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr, 359 s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); 360 } 361 } 362 363 // This function is called only for unqualified lookup 364 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); 365 366 /* If ident is "start at module scope", only look at module scope 367 */ 368 if (ident == Id.empty) 369 { 370 // Look for module scope 371 for (Scope* sc = &this; sc; sc = sc.enclosing) 372 { 373 assert(sc != sc.enclosing); 374 if (!sc.scopesym) 375 continue; 376 if (Dsymbol s = sc.scopesym.isModule()) 377 { 378 //printMsg("\tfound", s); 379 if (pscopesym) 380 *pscopesym = sc.scopesym; 381 return s; 382 } 383 } 384 return null; 385 } 386 387 Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) 388 { 389 import dmd.mtype; 390 if (!ad || !ad.aliasthis) 391 return null; 392 393 Declaration decl = ad.aliasthis.sym.isDeclaration(); 394 if (!decl) 395 return null; 396 397 Type t = decl.type; 398 ScopeDsymbol sds; 399 TypeClass tc; 400 TypeStruct ts; 401 switch(t.ty) 402 { 403 case Tstruct: 404 ts = cast(TypeStruct)t; 405 sds = ts.sym; 406 break; 407 case Tclass: 408 tc = cast(TypeClass)t; 409 sds = tc.sym; 410 break; 411 case Tinstance: 412 sds = (cast(TypeInstance)t).tempinst; 413 break; 414 case Tenum: 415 sds = (cast(TypeEnum)t).sym; 416 break; 417 default: break; 418 } 419 420 if (!sds) 421 return null; 422 423 Dsymbol ret = sds.search(loc, ident, flags); 424 if (ret) 425 { 426 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 427 *exp = new DotIdExp(loc, *exp, ident); 428 return ret; 429 } 430 431 if (!ts && !tc) 432 return null; 433 434 Dsymbol s; 435 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 436 if (ts && !(ts.att & AliasThisRec.tracing)) 437 { 438 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracing); 439 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 440 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracing); 441 } 442 else if(tc && !(tc.att & AliasThisRec.tracing)) 443 { 444 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracing); 445 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 446 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracing); 447 } 448 return s; 449 } 450 451 Dsymbol searchScopes(int flags) 452 { 453 for (Scope* sc = &this; sc; sc = sc.enclosing) 454 { 455 assert(sc != sc.enclosing); 456 if (!sc.scopesym) 457 continue; 458 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); 459 460 if (sc.scopesym.isModule()) 461 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 462 else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration()) 463 continue; // C doesn't have struct scope 464 465 if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) 466 { 467 if (flags & TagNameSpace) 468 { 469 // ImportC: if symbol is not a tag, look for it in tag table 470 if (!s.isScopeDsymbol()) 471 { 472 auto ps = cast(void*)s in sc._module.tagSymTab; 473 if (!ps) 474 goto NotFound; 475 s = *ps; 476 } 477 } 478 if (!(flags & (SearchImportsOnly | IgnoreErrors)) && 479 ident == Id.length && sc.scopesym.isArrayScopeSymbol() && 480 sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) 481 { 482 warning(s.loc, "array `length` hides other `length` name in outer scope"); 483 } 484 //printMsg("\tfound local", s); 485 if (pscopesym) 486 *pscopesym = sc.scopesym; 487 return s; 488 } 489 490 NotFound: 491 if (global.params.fixAliasThis) 492 { 493 Expression exp = new ThisExp(loc); 494 Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp); 495 if (aliasSym) 496 { 497 //printf("found aliassym: %s\n", aliasSym.toChars()); 498 if (pscopesym) 499 *pscopesym = new ExpressionDsymbol(exp); 500 return aliasSym; 501 } 502 } 503 504 // Stop when we hit a module, but keep going if that is not just under the global scope 505 if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing)) 506 break; 507 } 508 return null; 509 } 510 511 if (this.flags & SCOPE.ignoresymbolvisibility) 512 flags |= IgnoreSymbolVisibility; 513 514 // First look in local scopes 515 Dsymbol s = searchScopes(flags | SearchLocalsOnly); 516 version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); 517 if (!s) 518 { 519 // Second look in imported modules 520 s = searchScopes(flags | SearchImportsOnly); 521 version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); 522 } 523 return s; 524 } 525 526 extern (D) Dsymbol search_correct(Identifier ident) 527 { 528 if (global.gag) 529 return null; // don't do it for speculative compiles; too time consuming 530 531 /************************************************ 532 * Given the failed search attempt, try to find 533 * one with a close spelling. 534 * Params: 535 * seed = identifier to search for 536 * cost = set to the cost, which rises with each outer scope 537 * Returns: 538 * Dsymbol if found, null if not 539 */ 540 extern (D) Dsymbol scope_search_fp(const(char)[] seed, out int cost) 541 { 542 //printf("scope_search_fp('%s')\n", seed); 543 /* If not in the lexer's string table, it certainly isn't in the symbol table. 544 * Doing this first is a lot faster. 545 */ 546 if (!seed.length) 547 return null; 548 Identifier id = Identifier.lookup(seed); 549 if (!id) 550 return null; 551 Scope* sc = &this; 552 Module.clearCache(); 553 Dsymbol scopesym = null; 554 Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); 555 if (!s) 556 return null; 557 558 // Do not show `@disable`d declarations 559 if (auto decl = s.isDeclaration()) 560 if (decl.storage_class & STC.disable) 561 return null; 562 // Or `deprecated` ones if we're not in a deprecated scope 563 if (s.isDeprecated() && !sc.isDeprecated()) 564 return null; 565 566 for (cost = 0; sc; sc = sc.enclosing, ++cost) 567 if (sc.scopesym == scopesym) 568 break; 569 if (scopesym != s.parent) 570 { 571 ++cost; // got to the symbol through an import 572 if (s.visible().kind == Visibility.Kind.private_) 573 return null; 574 } 575 return s; 576 } 577 578 Dsymbol scopesym = null; 579 // search for exact name first 580 if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors)) 581 return s; 582 return speller!scope_search_fp(ident.toString()); 583 } 584 585 /************************************ 586 * Maybe `ident` was a C or C++ name. Check for that, 587 * and suggest the D equivalent. 588 * Params: 589 * ident = unknown identifier 590 * Returns: 591 * D identifier string if found, null if not 592 */ 593 extern (D) static const(char)* search_correct_C(Identifier ident) 594 { 595 import dmd.astenums : Twchar; 596 TOK tok; 597 if (ident == Id.NULL) 598 tok = TOK.null_; 599 else if (ident == Id.TRUE) 600 tok = TOK.true_; 601 else if (ident == Id.FALSE) 602 tok = TOK.false_; 603 else if (ident == Id.unsigned) 604 tok = TOK.uns32; 605 else if (ident == Id.wchar_t) 606 tok = target.c.wchar_tsize == 2 ? TOK.wchar_ : TOK.dchar_; 607 else 608 return null; 609 return Token.toChars(tok); 610 } 611 612 /*************************** 613 * Find the innermost scope with a symbol table. 614 * Returns: 615 * innermost scope, null if none 616 */ 617 extern (D) Scope* inner() return 618 { 619 for (Scope* sc = &this; sc; sc = sc.enclosing) 620 { 621 if (sc.scopesym) 622 return sc; 623 } 624 return null; 625 } 626 627 /****************************** 628 * Add symbol s to innermost symbol table. 629 * Params: 630 * s = symbol to insert 631 * Returns: 632 * null if already in table, `s` if not 633 */ 634 extern (D) Dsymbol insert(Dsymbol s) 635 { 636 //printf("insert() %s\n", s.toChars()); 637 if (VarDeclaration vd = s.isVarDeclaration()) 638 { 639 if (lastVar) 640 vd.lastVar = lastVar; 641 lastVar = vd; 642 } 643 else if (WithScopeSymbol ss = s.isWithScopeSymbol()) 644 { 645 if (VarDeclaration vd = ss.withstate.wthis) 646 { 647 if (lastVar) 648 vd.lastVar = lastVar; 649 lastVar = vd; 650 } 651 return null; 652 } 653 654 auto scopesym = inner().scopesym; 655 //printf("\t\tscopesym = %p\n", scopesym); 656 if (!scopesym.symtab) 657 scopesym.symtab = new DsymbolTable(); 658 if (!(flags & SCOPE.Cfile)) 659 return scopesym.symtabInsert(s); 660 661 // ImportC insert 662 if (!scopesym.symtabInsert(s)) // if already in table 663 { 664 Dsymbol s2 = scopesym.symtabLookup(s, s.ident); // s2 is existing entry 665 return handleTagSymbols(this, s, s2, scopesym); 666 } 667 return s; // inserted 668 } 669 670 /******************************************** 671 * Search enclosing scopes for ScopeDsymbol. 672 */ 673 extern (D) ScopeDsymbol getScopesym() 674 { 675 for (Scope* sc = &this; sc; sc = sc.enclosing) 676 { 677 if (sc.scopesym) 678 return sc.scopesym; 679 } 680 return null; // not found 681 } 682 683 /******************************************** 684 * Search enclosing scopes for ClassDeclaration. 685 */ 686 extern (D) ClassDeclaration getClassScope() 687 { 688 for (Scope* sc = &this; sc; sc = sc.enclosing) 689 { 690 if (!sc.scopesym) 691 continue; 692 if (ClassDeclaration cd = sc.scopesym.isClassDeclaration()) 693 return cd; 694 } 695 return null; 696 } 697 698 /******************************************** 699 * Search enclosing scopes for ClassDeclaration or StructDeclaration. 700 */ 701 extern (D) AggregateDeclaration getStructClassScope() 702 { 703 for (Scope* sc = &this; sc; sc = sc.enclosing) 704 { 705 if (!sc.scopesym) 706 continue; 707 if (AggregateDeclaration ad = sc.scopesym.isClassDeclaration()) 708 return ad; 709 if (AggregateDeclaration ad = sc.scopesym.isStructDeclaration()) 710 return ad; 711 } 712 return null; 713 } 714 715 /******************************************** 716 * Find the lexically enclosing function (if any). 717 * 718 * This function skips through generated FuncDeclarations, 719 * e.g. rewritten foreach bodies. 720 * 721 * Returns: the function or null 722 */ 723 extern (D) inout(FuncDeclaration) getEnclosingFunction() inout 724 { 725 if (!this.func) 726 return null; 727 728 auto fd = cast(FuncDeclaration) this.func; 729 730 // Look through foreach bodies rewritten as delegates 731 while (fd.fes) 732 { 733 assert(fd.fes.func); 734 fd = fd.fes.func; 735 } 736 737 return cast(inout(FuncDeclaration)) fd; 738 } 739 740 /******************************************* 741 * For TemplateDeclarations, we need to remember the Scope 742 * where it was declared. So mark the Scope as not 743 * to be free'd. 744 */ 745 extern (D) void setNoFree() 746 { 747 //int i = 0; 748 //printf("Scope::setNoFree(this = %p)\n", this); 749 for (Scope* sc = &this; sc; sc = sc.enclosing) 750 { 751 //printf("\tsc = %p\n", sc); 752 sc.nofree = true; 753 assert(!(flags & SCOPE.free)); 754 //assert(sc != sc.enclosing); 755 //assert(!sc.enclosing || sc != sc.enclosing.enclosing); 756 //if (++i == 10) 757 // assert(0); 758 } 759 } 760 /****************************** 761 */ 762 extern (D) structalign_t alignment() 763 { 764 if (aligndecl) 765 { 766 auto ad = aligndecl.getAlignment(&this); 767 return ad.salign; 768 } 769 else 770 { 771 structalign_t sa; 772 sa.setDefault(); 773 return sa; 774 } 775 } 776 @safe @nogc pure nothrow const: 777 /********************************** 778 * Checks whether the current scope (or any of its parents) is deprecated. 779 * 780 * Returns: `true` if this or any parent scope is deprecated, `false` otherwise` 781 */ 782 extern (D) bool isDeprecated() 783 { 784 for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent)) 785 { 786 if (sp.isDeprecated()) 787 return true; 788 } 789 for (const(Scope)* sc2 = &this; sc2; sc2 = sc2.enclosing) 790 { 791 if (sc2.scopesym && sc2.scopesym.isDeprecated()) 792 return true; 793 794 // If inside a StorageClassDeclaration that is deprecated 795 if (sc2.stc & STC.deprecated_) 796 return true; 797 } 798 if (_module.md && _module.md.isdeprecated) 799 { 800 return true; 801 } 802 return false; 803 } 804 /** 805 * dmd relies on mutation of state during semantic analysis, however 806 * sometimes semantic is being performed in a speculative context that should 807 * not have any visible effect on the rest of the compilation: for example when compiling 808 * a typeof() or __traits(compiles). 809 * 810 * Returns: `true` if this `Scope` is known to be from one of these speculative contexts 811 */ 812 extern (D) bool isFromSpeculativeSemanticContext() scope 813 { 814 return this.intypeof || this.flags & SCOPE.compile; 815 } 816 817 818 /** 819 * Returns: true if the code needs to go all the way through to code generation. 820 * This implies things like needing lowering to simpler forms. 821 */ 822 extern (D) bool needsCodegen() 823 { 824 return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0; 825 } 826 }