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.errorsink; 33 import dmd.func; 34 import dmd.globals; 35 import dmd.id; 36 import dmd.identifier; 37 import dmd.location; 38 import dmd.common.outbuffer; 39 import dmd.root.rmem; 40 import dmd.root.speller; 41 import dmd.statement; 42 import dmd.target; 43 import dmd.tokens; 44 45 //version=LOGSEARCH; 46 47 48 // List of flags that can be applied to this `Scope` 49 enum SCOPE 50 { 51 ctor = 0x0001, /// constructor type 52 noaccesscheck = 0x0002, /// don't do access checks 53 condition = 0x0004, /// inside static if/assert condition 54 debug_ = 0x0008, /// inside debug conditional 55 constraint = 0x0010, /// inside template constraint 56 invariant_ = 0x0020, /// inside invariant code 57 require = 0x0040, /// inside in contract code 58 ensure = 0x0060, /// inside out contract code 59 contract = 0x0060, /// [mask] we're inside contract code 60 ctfe = 0x0080, /// inside a ctfe-only expression 61 compile = 0x0100, /// inside __traits(compile) 62 ignoresymbolvisibility = 0x0200, /// ignore symbol visibility 63 /// https://issues.dlang.org/show_bug.cgi?id=15907 64 Cfile = 0x0800, /// C semantics apply 65 free = 0x8000, /// is on free list 66 67 fullinst = 0x10000, /// fully instantiate templates 68 ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block 69 } 70 71 /// Flags that are carried along with a scope push() 72 private enum PersistentFlags = 73 SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | 74 SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | 75 SCOPE.Cfile | SCOPE.ctfeBlock; 76 77 extern (C++) struct Scope 78 { 79 Scope* enclosing; /// enclosing Scope 80 81 Module _module; /// Root module 82 ScopeDsymbol scopesym; /// current symbol 83 FuncDeclaration func; /// function we are in 84 VarDeclaration varDecl; /// variable we are in during semantic2 85 Dsymbol parent; /// parent to use 86 LabelStatement slabel; /// enclosing labelled statement 87 SwitchStatement sw; /// enclosing switch statement 88 Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement 89 TryFinallyStatement tf; /// enclosing try finally statement 90 ScopeGuardStatement os; /// enclosing scope(xxx) statement 91 Statement sbreak; /// enclosing statement that supports "break" 92 Statement scontinue; /// enclosing statement that supports "continue" 93 ForeachStatement fes; /// if nested function for ForeachStatement, this is it 94 Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ 95 Dsymbol inunion; /// != null if processing members of a union 96 bool nofree; /// true if shouldn't free it 97 bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) 98 int intypeof; /// in typeof(exp) 99 VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init 100 ErrorSink eSink; /// sink for error messages 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 149 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 163 extern (D) static Scope* createGlobal(Module _module, ErrorSink eSink) 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 sc.eSink = eSink; 172 assert(eSink); 173 // Add top level package as member of this global scope 174 Dsymbol m = _module; 175 while (m.parent) 176 m = m.parent; 177 m.addMember(null, sc.scopesym); 178 m.parent = null; // got changed by addMember() 179 if (_module.filetype == FileType.c) 180 sc.flags |= SCOPE.Cfile; 181 // Create the module scope underneath the global scope 182 sc = sc.push(_module); 183 sc.parent = _module; 184 return sc; 185 } 186 187 extern (D) Scope* copy() 188 { 189 Scope* sc = Scope.alloc(); 190 *sc = this; 191 /* https://issues.dlang.org/show_bug.cgi?id=11777 192 * The copied scope should not inherit fieldinit. 193 */ 194 sc.ctorflow.fieldinit = null; 195 return sc; 196 } 197 198 extern (D) Scope* push() 199 { 200 Scope* s = copy(); 201 //printf("Scope::push(this = %p) new = %p\n", this, s); 202 assert(!(flags & SCOPE.free)); 203 s.scopesym = null; 204 s.enclosing = &this; 205 debug 206 { 207 if (enclosing) 208 assert(!(enclosing.flags & SCOPE.free)); 209 if (s == enclosing) 210 { 211 printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing); 212 } 213 assert(s != enclosing); 214 } 215 s.slabel = null; 216 s.nofree = false; 217 s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup; 218 s.flags = (flags & PersistentFlags); 219 s.lastdc = null; 220 assert(&this != s); 221 return s; 222 } 223 224 extern (D) Scope* push(ScopeDsymbol ss) 225 { 226 //printf("Scope::push(%s)\n", ss.toChars()); 227 Scope* s = push(); 228 s.scopesym = ss; 229 return s; 230 } 231 232 extern (D) Scope* pop() 233 { 234 //printf("Scope::pop() %p nofree = %d\n", this, nofree); 235 if (enclosing) 236 enclosing.ctorflow.OR(ctorflow); 237 ctorflow.freeFieldinit(); 238 239 Scope* enc = enclosing; 240 if (!nofree) 241 { 242 if (mem.isGCEnabled) 243 this = this.init; 244 enclosing = freelist; 245 freelist = &this; 246 flags |= SCOPE.free; 247 } 248 return enc; 249 } 250 251 /************************* 252 * Similar to pop(), but the results in `this` are not folded 253 * into `enclosing`. 254 */ 255 extern (D) void detach() 256 { 257 ctorflow.freeFieldinit(); 258 enclosing = null; 259 pop(); 260 } 261 262 extern (D) Scope* startCTFE() 263 { 264 Scope* sc = this.push(); 265 sc.flags = this.flags | SCOPE.ctfe; 266 version (none) 267 { 268 /* TODO: Currently this is not possible, because we need to 269 * unspeculative some types and symbols if they are necessary for the 270 * final executable. Consider: 271 * 272 * struct S(T) { 273 * string toString() const { return "instantiated"; } 274 * } 275 * enum x = S!int(); 276 * void main() { 277 * // To call x.toString in runtime, compiler should unspeculative S!int. 278 * assert(x.toString() == "instantiated"); 279 * } 280 * 281 * This results in an undefined reference to `RTInfoImpl`: 282 * class C { int a,b,c; int* p,q; } 283 * void test() { C c = new C(); } 284 */ 285 // If a template is instantiated from CT evaluated expression, 286 // compiler can elide its code generation. 287 sc.tinst = null; 288 sc.minst = null; 289 } 290 return sc; 291 } 292 293 extern (D) Scope* endCTFE() 294 { 295 assert(flags & SCOPE.ctfe); 296 return pop(); 297 } 298 299 300 /******************************* 301 * Merge results of `ctorflow` into `this`. 302 * Params: 303 * loc = for error messages 304 * ctorflow = flow results to merge in 305 */ 306 extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow) 307 { 308 if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper)) 309 error(loc, "one path skips constructor"); 310 311 const fies = ctorflow.fieldinit; 312 if (this.ctorflow.fieldinit.length && fies.length) 313 { 314 FuncDeclaration f = func; 315 if (fes) 316 f = fes.func; 317 auto ad = f.isMemberDecl(); 318 assert(ad); 319 foreach (i, v; ad.fields) 320 { 321 bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); 322 auto fieldInit = &this.ctorflow.fieldinit[i]; 323 const fiesCurrent = fies[i]; 324 if (fieldInit.loc is Loc.init) 325 fieldInit.loc = fiesCurrent.loc; 326 if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit) 327 { 328 error(loc, "one path skips field `%s`", v.toChars()); 329 } 330 } 331 } 332 } 333 334 /************************************ 335 * Perform unqualified name lookup by following the chain of scopes up 336 * until found. 337 * 338 * Params: 339 * loc = location to use for error messages 340 * ident = name to look up 341 * pscopesym = if supplied and name is found, set to scope that ident was found in 342 * flags = modify search based on flags 343 * 344 * Returns: 345 * symbol if found, null if not 346 */ 347 extern (D) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) 348 { 349 version (LOGSEARCH) 350 { 351 printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags); 352 // Print scope chain 353 for (Scope* sc = &this; sc; sc = sc.enclosing) 354 { 355 if (!sc.scopesym) 356 continue; 357 printf("\tscope %s\n", sc.scopesym.toChars()); 358 } 359 360 static void printMsg(string txt, Dsymbol s) 361 { 362 printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr, 363 s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); 364 } 365 } 366 367 // This function is called only for unqualified lookup 368 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); 369 370 /* If ident is "start at module scope", only look at module scope 371 */ 372 if (ident == Id.empty) 373 { 374 // Look for module scope 375 for (Scope* sc = &this; sc; sc = sc.enclosing) 376 { 377 assert(sc != sc.enclosing); 378 if (!sc.scopesym) 379 continue; 380 if (Dsymbol s = sc.scopesym.isModule()) 381 { 382 //printMsg("\tfound", s); 383 if (pscopesym) 384 *pscopesym = sc.scopesym; 385 return s; 386 } 387 } 388 return null; 389 } 390 391 Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) 392 { 393 import dmd.mtype; 394 if (!ad || !ad.aliasthis) 395 return null; 396 397 Declaration decl = ad.aliasthis.sym.isDeclaration(); 398 if (!decl) 399 return null; 400 401 Type t = decl.type; 402 ScopeDsymbol sds; 403 TypeClass tc; 404 TypeStruct ts; 405 switch(t.ty) 406 { 407 case Tstruct: 408 ts = cast(TypeStruct)t; 409 sds = ts.sym; 410 break; 411 case Tclass: 412 tc = cast(TypeClass)t; 413 sds = tc.sym; 414 break; 415 case Tinstance: 416 sds = (cast(TypeInstance)t).tempinst; 417 break; 418 case Tenum: 419 sds = (cast(TypeEnum)t).sym; 420 break; 421 default: break; 422 } 423 424 if (!sds) 425 return null; 426 427 Dsymbol ret = sds.search(loc, ident, flags); 428 if (ret) 429 { 430 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 431 *exp = new DotIdExp(loc, *exp, ident); 432 return ret; 433 } 434 435 if (!ts && !tc) 436 return null; 437 438 Dsymbol s; 439 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 440 if (ts && !(ts.att & AliasThisRec.tracing)) 441 { 442 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracing); 443 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 444 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracing); 445 } 446 else if(tc && !(tc.att & AliasThisRec.tracing)) 447 { 448 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracing); 449 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 450 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracing); 451 } 452 return s; 453 } 454 455 Dsymbol searchScopes(int flags) 456 { 457 for (Scope* sc = &this; sc; sc = sc.enclosing) 458 { 459 assert(sc != sc.enclosing); 460 if (!sc.scopesym) 461 continue; 462 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); 463 464 if (sc.scopesym.isModule()) 465 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 466 else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration()) 467 continue; // C doesn't have struct scope 468 469 if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) 470 { 471 if (flags & TagNameSpace) 472 { 473 // ImportC: if symbol is not a tag, look for it in tag table 474 if (!s.isScopeDsymbol()) 475 { 476 auto ps = cast(void*)s in sc._module.tagSymTab; 477 if (!ps) 478 goto NotFound; 479 s = *ps; 480 } 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 524 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 */ 591 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 @safe 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 extern (D) ScopeDsymbol getScopesym() @safe 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 (D) ClassDeclaration getClassScope() @safe 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 (D) AggregateDeclaration getStructClassScope() @safe 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 extern (D) 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() @safe 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 extern (D) structalign_t alignment() 761 { 762 if (aligndecl) 763 { 764 auto ad = aligndecl.getAlignment(&this); 765 return ad.salign; 766 } 767 else 768 { 769 structalign_t sa; 770 sa.setDefault(); 771 return sa; 772 } 773 } 774 @safe @nogc pure nothrow const: 775 /********************************** 776 * Checks whether the current scope (or any of its parents) is deprecated. 777 * 778 * Returns: `true` if this or any parent scope is deprecated, `false` otherwise` 779 */ 780 extern (D) bool isDeprecated() 781 { 782 for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent)) 783 { 784 if (sp.isDeprecated()) 785 return true; 786 } 787 for (const(Scope)* sc2 = &this; sc2; sc2 = sc2.enclosing) 788 { 789 if (sc2.scopesym && sc2.scopesym.isDeprecated()) 790 return true; 791 792 // If inside a StorageClassDeclaration that is deprecated 793 if (sc2.stc & STC.deprecated_) 794 return true; 795 } 796 if (_module.md && _module.md.isdeprecated) 797 { 798 return true; 799 } 800 return false; 801 } 802 /** 803 * dmd relies on mutation of state during semantic analysis, however 804 * sometimes semantic is being performed in a speculative context that should 805 * not have any visible effect on the rest of the compilation: for example when compiling 806 * a typeof() or __traits(compiles). 807 * 808 * Returns: `true` if this `Scope` is known to be from one of these speculative contexts 809 */ 810 extern (D) bool isFromSpeculativeSemanticContext() scope 811 { 812 return this.intypeof || this.flags & SCOPE.compile; 813 } 814 815 816 /** 817 * Returns: true if the code needs to go all the way through to code generation. 818 * This implies things like needing lowering to simpler forms. 819 */ 820 extern (D) bool needsCodegen() 821 { 822 return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0; 823 } 824 }