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