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 }