1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
9  */
10 
11 #include "root/dsystem.h"               // strlen()
12 #include "root/root.h"
13 #include "root/rmem.h"
14 #include "root/speller.h"
15 
16 #include "mars.h"
17 #include "init.h"
18 #include "identifier.h"
19 #include "scope.h"
20 #include "attrib.h"
21 #include "dsymbol.h"
22 #include "declaration.h"
23 #include "statement.h"
24 #include "aggregate.h"
25 #include "module.h"
26 #include "id.h"
27 #include "target.h"
28 #include "template.h"
29 
30 Scope *Scope::freelist = NULL;
31 
allocFieldinit(Scope * sc,size_t dim)32 void allocFieldinit(Scope *sc, size_t dim)
33 {
34     sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
35     sc->fieldinit_dim = dim;
36 }
37 
freeFieldinit(Scope * sc)38 void freeFieldinit(Scope *sc)
39 {
40     if (sc->fieldinit)
41         mem.xfree(sc->fieldinit);
42     sc->fieldinit = NULL;
43     sc->fieldinit_dim = 0;
44 }
45 
alloc()46 Scope *Scope::alloc()
47 {
48     if (freelist)
49     {
50         Scope *s = freelist;
51         freelist = s->enclosing;
52         //printf("freelist %p\n", s);
53         assert(s->flags & SCOPEfree);
54         s->flags &= ~SCOPEfree;
55         return s;
56     }
57 
58     return new Scope();
59 }
60 
Scope()61 Scope::Scope()
62 {
63     // Create root scope
64 
65     //printf("Scope::Scope() %p\n", this);
66     this->_module = NULL;
67     this->scopesym = NULL;
68     this->enclosing = NULL;
69     this->parent = NULL;
70     this->sw = NULL;
71     this->tf = NULL;
72     this->os = NULL;
73     this->tinst = NULL;
74     this->minst = NULL;
75     this->sbreak = NULL;
76     this->scontinue = NULL;
77     this->fes = NULL;
78     this->callsc = NULL;
79     this->aligndecl = NULL;
80     this->func = NULL;
81     this->slabel = NULL;
82     this->linkage = LINKd;
83     this->cppmangle = CPPMANGLEdefault;
84     this->inlining = PINLINEdefault;
85     this->protection = Prot(Prot::public_);
86     this->explicitProtection = 0;
87     this->stc = 0;
88     this->depdecl = NULL;
89     this->inunion = 0;
90     this->nofree = 0;
91     this->noctor = 0;
92     this->intypeof = 0;
93     this->lastVar = NULL;
94     this->callSuper = 0;
95     this->fieldinit = NULL;
96     this->fieldinit_dim = 0;
97     this->flags = 0;
98     this->lastdc = NULL;
99     this->anchorCounts = NULL;
100     this->prevAnchor = NULL;
101     this->userAttribDecl = NULL;
102 }
103 
copy()104 Scope *Scope::copy()
105 {
106     Scope *sc = Scope::alloc();
107     *sc = *this;    // memcpy
108 
109     /* Bugzilla 11777: The copied scope should not inherit fieldinit.
110      */
111     sc->fieldinit = NULL;
112 
113     return sc;
114 }
115 
createGlobal(Module * _module)116 Scope *Scope::createGlobal(Module *_module)
117 {
118     Scope *sc = Scope::alloc();
119     *sc = Scope();  // memset
120 
121     sc->aligndecl = NULL;
122     sc->linkage = LINKd;
123     sc->inlining = PINLINEdefault;
124     sc->protection = Prot(Prot::public_);
125 
126     sc->_module = _module;
127 
128     sc->tinst = NULL;
129     sc->minst = _module;
130 
131     sc->scopesym = new ScopeDsymbol();
132     sc->scopesym->symtab = new DsymbolTable();
133 
134     // Add top level package as member of this global scope
135     Dsymbol *m = _module;
136     while (m->parent)
137         m = m->parent;
138     m->addMember(NULL, sc->scopesym);
139     m->parent = NULL;                   // got changed by addMember()
140 
141     // Create the module scope underneath the global scope
142     sc = sc->push(_module);
143     sc->parent = _module;
144     return sc;
145 }
146 
push()147 Scope *Scope::push()
148 {
149     Scope *s = copy();
150 
151     //printf("Scope::push(this = %p) new = %p\n", this, s);
152     assert(!(flags & SCOPEfree));
153     s->scopesym = NULL;
154     s->enclosing = this;
155     s->slabel = NULL;
156     s->nofree = 0;
157     s->fieldinit = saveFieldInit();
158     s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
159                          SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
160                          SCOPEprintf | SCOPEscanf));
161     s->lastdc = NULL;
162 
163     assert(this != s);
164     return s;
165 }
166 
push(ScopeDsymbol * ss)167 Scope *Scope::push(ScopeDsymbol *ss)
168 {
169     //printf("Scope::push(%s)\n", ss->toChars());
170     Scope *s = push();
171     s->scopesym = ss;
172     return s;
173 }
174 
pop()175 Scope *Scope::pop()
176 {
177     //printf("Scope::pop() %p nofree = %d\n", this, nofree);
178     Scope *enc = enclosing;
179 
180     if (enclosing)
181     {
182         enclosing->callSuper |= callSuper;
183         if (fieldinit)
184         {
185             if (enclosing->fieldinit)
186             {
187                 assert(fieldinit != enclosing->fieldinit);
188                 size_t dim = fieldinit_dim;
189                 for (size_t i = 0; i < dim; i++)
190                     enclosing->fieldinit[i] |= fieldinit[i];
191             }
192             freeFieldinit(this);
193         }
194     }
195 
196     if (!nofree)
197     {
198         enclosing = freelist;
199         freelist = this;
200         flags |= SCOPEfree;
201     }
202 
203     return enc;
204 }
205 
startCTFE()206 Scope *Scope::startCTFE()
207 {
208     Scope *sc = this->push();
209     sc->flags = this->flags | SCOPEctfe;
210     return sc;
211 }
212 
endCTFE()213 Scope *Scope::endCTFE()
214 {
215     assert(flags & SCOPEctfe);
216     return pop();
217 }
218 
mergeCallSuper(Loc loc,unsigned cs)219 void Scope::mergeCallSuper(Loc loc, unsigned cs)
220 {
221     // This does a primitive flow analysis to support the restrictions
222     // regarding when and how constructors can appear.
223     // It merges the results of two paths.
224     // The two paths are callSuper and cs; the result is merged into callSuper.
225 
226     if (cs != callSuper)
227     {
228         // Have ALL branches called a constructor?
229         int aAll = (cs        & (CSXthis_ctor | CSXsuper_ctor)) != 0;
230         int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
231 
232         // Have ANY branches called a constructor?
233         bool aAny = (cs        & CSXany_ctor) != 0;
234         bool bAny = (callSuper & CSXany_ctor) != 0;
235 
236         // Have any branches returned?
237         bool aRet = (cs        & CSXreturn) != 0;
238         bool bRet = (callSuper & CSXreturn) != 0;
239 
240         // Have any branches halted?
241         bool aHalt = (cs        & CSXhalt) != 0;
242         bool bHalt = (callSuper & CSXhalt) != 0;
243 
244         bool ok = true;
245 
246         if (aHalt && bHalt)
247         {
248             callSuper = CSXhalt;
249         }
250         else if ((!aHalt && aRet && !aAny && bAny) ||
251                  (!bHalt && bRet && !bAny && aAny))
252         {
253             // If one has returned without a constructor call, there must be never
254             // have been ctor calls in the other.
255             ok = false;
256         }
257         else if (aHalt || (aRet && aAll))
258         {
259             // If one branch has called a ctor and then exited, anything the
260             // other branch has done is OK (except returning without a
261             // ctor call, but we already checked that).
262             callSuper |= cs & (CSXany_ctor | CSXlabel);
263         }
264         else if (bHalt || (bRet && bAll))
265         {
266             callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
267         }
268         else
269         {
270             // Both branches must have called ctors, or both not.
271             ok = (aAll == bAll);
272             // If one returned without a ctor, we must remember that
273             // (Don't bother if we've already found an error)
274             if (ok && aRet && !aAny)
275                 callSuper |= CSXreturn;
276             callSuper |= cs & (CSXany_ctor | CSXlabel);
277         }
278         if (!ok)
279             error(loc, "one path skips constructor");
280     }
281 }
282 
saveFieldInit()283 unsigned *Scope::saveFieldInit()
284 {
285     unsigned *fi = NULL;
286     if (fieldinit)  // copy
287     {
288         size_t dim = fieldinit_dim;
289         fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
290         for (size_t i = 0; i < dim; i++)
291             fi[i] = fieldinit[i];
292     }
293     return fi;
294 }
295 
296 /****************************************
297  * Merge `b` flow analysis results into `a`.
298  * Params:
299  *      a = the path to merge fi into
300  *      b = the other path
301  * Returns:
302  *      false means either `a` or `b` skips initialization
303  */
mergeFieldInit(unsigned & a,const unsigned b)304 static bool mergeFieldInit(unsigned &a, const unsigned b)
305 {
306     if (b == a)
307         return true;
308 
309     // Have any branches returned?
310     bool aRet = (a & CSXreturn) != 0;
311     bool bRet = (b & CSXreturn) != 0;
312 
313     // Have any branches halted?
314     bool aHalt = (a & CSXhalt) != 0;
315     bool bHalt = (b & CSXhalt) != 0;
316 
317     if (aHalt && bHalt)
318     {
319         a = CSXhalt;
320         return true;
321     }
322 
323     // The logic here is to prefer the branch that neither halts nor returns.
324     bool ok;
325     if (!bHalt && bRet)
326     {
327         // Branch b returns, no merging required.
328         ok = (b & CSXthis_ctor);
329     }
330     else if (!aHalt && aRet)
331     {
332         // Branch a returns, but b doesn't, b takes precedence.
333         ok = (a & CSXthis_ctor);
334         a = b;
335     }
336     else if (bHalt)
337     {
338         // Branch b halts, no merging required.
339         ok = (a & CSXthis_ctor);
340     }
341     else if (aHalt)
342     {
343         // Branch a halts, but b doesn't, b takes precedence
344         ok = (b & CSXthis_ctor);
345         a = b;
346     }
347     else
348     {
349         // Neither branch returns nor halts, merge flags
350         ok = !((a ^ b) & CSXthis_ctor);
351         a |= b;
352     }
353     return ok;
354 }
355 
mergeFieldInit(Loc loc,unsigned * fies)356 void Scope::mergeFieldInit(Loc loc, unsigned *fies)
357 {
358     if (fieldinit && fies)
359     {
360         FuncDeclaration *f = func;
361         if (fes) f = fes->func;
362         AggregateDeclaration *ad = f->isMember2();
363         assert(ad);
364 
365         for (size_t i = 0; i < ad->fields.length; i++)
366         {
367             VarDeclaration *v = ad->fields[i];
368             bool mustInit = (v->storage_class & STCnodefaultctor ||
369                              v->type->needsNested());
370 
371             if (!::mergeFieldInit(fieldinit[i], fies[i]) && mustInit)
372             {
373                 ::error(loc, "one path skips field %s", v->toChars());
374             }
375         }
376     }
377 }
378 
instantiatingModule()379 Module *Scope::instantiatingModule()
380 {
381     // TODO: in speculative context, returning 'module' is correct?
382     return minst ? minst : _module;
383 }
384 
searchScopes(Scope * scope,Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)385 static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
386 {
387     for (Scope *sc = scope; sc; sc = sc->enclosing)
388     {
389         assert(sc != sc->enclosing);
390         if (!sc->scopesym)
391             continue;
392         //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
393 
394         if (sc->scopesym->isModule())
395             flags |= SearchUnqualifiedModule;        // tell Module.search() that SearchLocalsOnly is to be obeyed
396 
397         if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
398         {
399             if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
400                 ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
401                 sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
402             {
403                 warning(s->loc, "array `length` hides other `length` name in outer scope");
404             }
405             if (pscopesym)
406                 *pscopesym = sc->scopesym;
407             return s;
408         }
409         // Stop when we hit a module, but keep going if that is not just under the global scope
410         if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
411             break;
412     }
413     return NULL;
414 }
415 
416 /************************************
417  * Perform unqualified name lookup by following the chain of scopes up
418  * until found.
419  *
420  * Params:
421  *  loc = location to use for error messages
422  *  ident = name to look up
423  *  pscopesym = if supplied and name is found, set to scope that ident was found in
424  *  flags = modify search based on flags
425  *
426  * Returns:
427  *  symbol if found, null if not
428  */
search(Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)429 Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
430 {
431     // This function is called only for unqualified lookup
432     assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
433 
434     /* If ident is "start at module scope", only look at module scope
435      */
436     if (ident == Id::empty)
437     {
438         // Look for module scope
439         for (Scope *sc = this; sc; sc = sc->enclosing)
440         {
441             assert(sc != sc->enclosing);
442             if (!sc->scopesym)
443                 continue;
444 
445             if (Dsymbol *s = sc->scopesym->isModule())
446             {
447                 if (pscopesym)
448                     *pscopesym = sc->scopesym;
449                 return s;
450             }
451         }
452         return NULL;
453     }
454 
455     if (this->flags & SCOPEignoresymbolvisibility)
456         flags |= IgnoreSymbolVisibility;
457 
458     // First look in local scopes
459     Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
460     if (!s)
461     {
462         // Second look in imported modules
463         s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
464     }
465     return s;
466 }
467 
insert(Dsymbol * s)468 Dsymbol *Scope::insert(Dsymbol *s)
469 {
470     if (VarDeclaration *vd = s->isVarDeclaration())
471     {
472         if (lastVar)
473             vd->lastVar = lastVar;
474         lastVar = vd;
475     }
476     else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
477     {
478         if (VarDeclaration *wthis = ss->withstate->wthis)
479         {
480             if (lastVar)
481                 wthis->lastVar = lastVar;
482             lastVar = wthis;
483         }
484         return NULL;
485     }
486     for (Scope *sc = this; sc; sc = sc->enclosing)
487     {
488         //printf("\tsc = %p\n", sc);
489         if (sc->scopesym)
490         {
491             //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
492             if (!sc->scopesym->symtab)
493                 sc->scopesym->symtab = new DsymbolTable();
494             return sc->scopesym->symtabInsert(s);
495         }
496     }
497     assert(0);
498     return NULL;
499 }
500 
501 /********************************************
502  * Search enclosing scopes for ClassDeclaration.
503  */
504 
getClassScope()505 ClassDeclaration *Scope::getClassScope()
506 {
507     for (Scope *sc = this; sc; sc = sc->enclosing)
508     {
509         if (!sc->scopesym)
510             continue;
511 
512         ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
513         if (cd)
514             return cd;
515     }
516     return NULL;
517 }
518 
519 /********************************************
520  * Search enclosing scopes for ClassDeclaration.
521  */
522 
getStructClassScope()523 AggregateDeclaration *Scope::getStructClassScope()
524 {
525     for (Scope *sc = this; sc; sc = sc->enclosing)
526     {
527         if (!sc->scopesym)
528             continue;
529 
530         AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
531         if (ad)
532             return ad;
533         ad = sc->scopesym->isStructDeclaration();
534         if (ad)
535             return ad;
536     }
537     return NULL;
538 }
539 
540 /*******************************************
541  * For TemplateDeclarations, we need to remember the Scope
542  * where it was declared. So mark the Scope as not
543  * to be free'd.
544  */
545 
setNoFree()546 void Scope::setNoFree()
547 {
548     //int i = 0;
549 
550     //printf("Scope::setNoFree(this = %p)\n", this);
551     for (Scope *sc = this; sc; sc = sc->enclosing)
552     {
553         //printf("\tsc = %p\n", sc);
554         sc->nofree = 1;
555 
556         assert(!(flags & SCOPEfree));
557         //assert(sc != sc->enclosing);
558         //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
559         //if (++i == 10)
560             //assert(0);
561     }
562 }
563 
alignment()564 structalign_t Scope::alignment()
565 {
566     if (aligndecl)
567         return aligndecl->getAlignment(this);
568     else
569         return STRUCTALIGN_DEFAULT;
570 }
571 
572 /************************************************
573  * Given the failed search attempt, try to find
574  * one with a close spelling.
575  */
576 
scope_search_fp(void * arg,const char * seed,int * cost)577 static void *scope_search_fp(void *arg, const char *seed, int* cost)
578 {
579     //printf("scope_search_fp('%s')\n", seed);
580 
581     /* If not in the lexer's string table, it certainly isn't in the symbol table.
582      * Doing this first is a lot faster.
583      */
584     size_t len = strlen(seed);
585     if (!len)
586         return NULL;
587     Identifier *id = Identifier::lookup(seed, len);
588     if (!id)
589         return NULL;
590 
591     Scope *sc = (Scope *)arg;
592     Module::clearCache();
593     Dsymbol *scopesym = NULL;
594     Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
595     if (s)
596     {
597         for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
598             if (sc->scopesym == scopesym)
599                 break;
600         if (scopesym != s->parent)
601         {
602             (*cost)++; // got to the symbol through an import
603             if (s->prot().kind == Prot::private_)
604                 return NULL;
605         }
606     }
607     return (void*)s;
608 }
609 
search_correct(Identifier * ident)610 Dsymbol *Scope::search_correct(Identifier *ident)
611 {
612     if (global.gag)
613         return NULL;            // don't do it for speculative compiles; too time consuming
614 
615     Dsymbol *scopesym = NULL;
616     // search for exact name first
617     if (Dsymbol *s = search(Loc(), ident, &scopesym, IgnoreErrors))
618         return s;
619     return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
620 }
621 
622 /************************************
623  * Maybe `ident` was a C or C++ name. Check for that,
624  * and suggest the D equivalent.
625  * Params:
626  *  ident = unknown identifier
627  * Returns:
628  *  D identifier string if found, null if not
629  */
search_correct_C(Identifier * ident)630 const char *Scope::search_correct_C(Identifier *ident)
631 {
632     TOK tok;
633     if (ident == Id::C_NULL)
634         tok = TOKnull;
635     else if (ident == Id::C_TRUE)
636         tok = TOKtrue;
637     else if (ident == Id::C_FALSE)
638         tok = TOKfalse;
639     else if (ident == Id::C_unsigned)
640         tok = TOKuns32;
641     else if (ident == Id::C_wchar_t)
642         tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
643     else
644         return NULL;
645     return Token::toChars(tok);
646 }
647