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