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