xref: /netbsd/external/gpl3/gcc/dist/gcc/d/dmd/dscope.d (revision f0fbc68b)
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