1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2019 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 "template.h"
28 
29 Scope *Scope::freelist = NULL;
30 
allocFieldinit(Scope * sc,size_t dim)31 void allocFieldinit(Scope *sc, size_t dim)
32 {
33     sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
34     sc->fieldinit_dim = dim;
35 }
36 
freeFieldinit(Scope * sc)37 void freeFieldinit(Scope *sc)
38 {
39     if (sc->fieldinit)
40         mem.xfree(sc->fieldinit);
41     sc->fieldinit = NULL;
42     sc->fieldinit_dim = 0;
43 }
44 
alloc()45 Scope *Scope::alloc()
46 {
47     if (freelist)
48     {
49         Scope *s = freelist;
50         freelist = s->enclosing;
51         //printf("freelist %p\n", s);
52         assert(s->flags & SCOPEfree);
53         s->flags &= ~SCOPEfree;
54         return s;
55     }
56 
57     return new Scope();
58 }
59 
Scope()60 Scope::Scope()
61 {
62     // Create root scope
63 
64     //printf("Scope::Scope() %p\n", this);
65     this->_module = NULL;
66     this->scopesym = NULL;
67     this->sds = 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(PROTpublic);
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(PROTpublic);
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->sds = NULL;
155     s->enclosing = this;
156     s->slabel = NULL;
157     s->nofree = 0;
158     s->fieldinit = saveFieldInit();
159     s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
160                          SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
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 
mergeFieldInit(unsigned & fieldInit,unsigned fi,bool mustInit)296 static bool mergeFieldInit(unsigned &fieldInit, unsigned fi, bool mustInit)
297 {
298     if (fi != fieldInit)
299     {
300         // Have any branches returned?
301         bool aRet = (fi        & CSXreturn) != 0;
302         bool bRet = (fieldInit & CSXreturn) != 0;
303 
304         // Have any branches halted?
305         bool aHalt = (fi        & CSXhalt) != 0;
306         bool bHalt = (fieldInit & CSXhalt) != 0;
307 
308         bool ok;
309 
310         if (aHalt && bHalt)
311         {
312             ok = true;
313             fieldInit = CSXhalt;
314         }
315         else if (!aHalt && aRet)
316         {
317             ok = !mustInit || (fi & CSXthis_ctor);
318             fieldInit = fieldInit;
319         }
320         else if (!bHalt && bRet)
321         {
322             ok = !mustInit || (fieldInit & CSXthis_ctor);
323             fieldInit = fi;
324         }
325         else if (aHalt)
326         {
327             ok = !mustInit || (fieldInit & CSXthis_ctor);
328             fieldInit = fieldInit;
329         }
330         else if (bHalt)
331         {
332             ok = !mustInit || (fi & CSXthis_ctor);
333             fieldInit = fi;
334         }
335         else
336         {
337             ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor);
338             fieldInit |= fi;
339         }
340 
341         return ok;
342     }
343     return true;
344 }
345 
mergeFieldInit(Loc loc,unsigned * fies)346 void Scope::mergeFieldInit(Loc loc, unsigned *fies)
347 {
348     if (fieldinit && fies)
349     {
350         FuncDeclaration *f = func;
351         if (fes) f = fes->func;
352         AggregateDeclaration *ad = f->isMember2();
353         assert(ad);
354 
355         for (size_t i = 0; i < ad->fields.dim; i++)
356         {
357             VarDeclaration *v = ad->fields[i];
358             bool mustInit = (v->storage_class & STCnodefaultctor ||
359                              v->type->needsNested());
360 
361             if (!::mergeFieldInit(fieldinit[i], fies[i], mustInit))
362             {
363                 ::error(loc, "one path skips field %s", ad->fields[i]->toChars());
364             }
365         }
366     }
367 }
368 
instantiatingModule()369 Module *Scope::instantiatingModule()
370 {
371     // TODO: in speculative context, returning 'module' is correct?
372     return minst ? minst : _module;
373 }
374 
searchScopes(Scope * scope,Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)375 static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
376 {
377     for (Scope *sc = scope; sc; sc = sc->enclosing)
378     {
379         assert(sc != sc->enclosing);
380         if (!sc->scopesym)
381             continue;
382         //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
383 
384         if (sc->scopesym->isModule())
385             flags |= SearchUnqualifiedModule;        // tell Module.search() that SearchLocalsOnly is to be obeyed
386 
387         if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
388         {
389             if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
390                 ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
391                 sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
392             {
393                 warning(s->loc, "array 'length' hides other 'length' name in outer scope");
394             }
395             if (pscopesym)
396                 *pscopesym = sc->scopesym;
397             return s;
398         }
399         // Stop when we hit a module, but keep going if that is not just under the global scope
400         if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
401             break;
402     }
403     return NULL;
404 }
405 
406 /************************************
407  * Perform unqualified name lookup by following the chain of scopes up
408  * until found.
409  *
410  * Params:
411  *  loc = location to use for error messages
412  *  ident = name to look up
413  *  pscopesym = if supplied and name is found, set to scope that ident was found in
414  *  flags = modify search based on flags
415  *
416  * Returns:
417  *  symbol if found, null if not
418  */
search(Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)419 Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
420 {
421     // This function is called only for unqualified lookup
422     assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
423 
424     /* If ident is "start at module scope", only look at module scope
425      */
426     if (ident == Id::empty)
427     {
428         // Look for module scope
429         for (Scope *sc = this; sc; sc = sc->enclosing)
430         {
431             assert(sc != sc->enclosing);
432             if (!sc->scopesym)
433                 continue;
434 
435             if (Dsymbol *s = sc->scopesym->isModule())
436             {
437                 if (pscopesym)
438                     *pscopesym = sc->scopesym;
439                 return s;
440             }
441         }
442         return NULL;
443     }
444 
445     if (this->flags & SCOPEignoresymbolvisibility)
446         flags |= IgnoreSymbolVisibility;
447 
448     Dsymbol *sold = NULL;
449     if (global.params.bug10378 || global.params.check10378)
450     {
451         sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility);
452         if (!global.params.check10378)
453             return sold;
454 
455         if (ident == Id::dollar) // Bugzilla 15825
456             return sold;
457 
458         // Search both ways
459     }
460 
461     // First look in local scopes
462     Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
463     if (!s)
464     {
465         // Second look in imported modules
466         s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
467         /** Still find private symbols, so that symbols that weren't access
468          * checked by the compiler remain usable.  Once the deprecation is over,
469          * this should be moved to search_correct instead.
470          */
471         if (!s && !(flags & IgnoreSymbolVisibility))
472         {
473             s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
474             if (!s)
475                 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility);
476 
477             if (s && !(flags & IgnoreErrors))
478                 ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars());
479         }
480     }
481 
482     if (global.params.check10378)
483     {
484         Dsymbol *snew = s;
485         if (sold != snew)
486             deprecation10378(loc, sold, snew);
487         if (global.params.bug10378)
488             s = sold;
489     }
490     return s;
491 }
492 
insert(Dsymbol * s)493 Dsymbol *Scope::insert(Dsymbol *s)
494 {
495     if (VarDeclaration *vd = s->isVarDeclaration())
496     {
497         if (lastVar)
498             vd->lastVar = lastVar;
499         lastVar = vd;
500     }
501     else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
502     {
503         if (VarDeclaration *vd = ss->withstate->wthis)
504         {
505             if (lastVar)
506                 vd->lastVar = lastVar;
507             lastVar = vd;
508         }
509         return NULL;
510     }
511     for (Scope *sc = this; sc; sc = sc->enclosing)
512     {
513         //printf("\tsc = %p\n", sc);
514         if (sc->scopesym)
515         {
516             //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
517             if (!sc->scopesym->symtab)
518                 sc->scopesym->symtab = new DsymbolTable();
519             return sc->scopesym->symtabInsert(s);
520         }
521     }
522     assert(0);
523     return NULL;
524 }
525 
526 /********************************************
527  * Search enclosing scopes for ClassDeclaration.
528  */
529 
getClassScope()530 ClassDeclaration *Scope::getClassScope()
531 {
532     for (Scope *sc = this; sc; sc = sc->enclosing)
533     {
534         if (!sc->scopesym)
535             continue;
536 
537         ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
538         if (cd)
539             return cd;
540     }
541     return NULL;
542 }
543 
544 /********************************************
545  * Search enclosing scopes for ClassDeclaration.
546  */
547 
getStructClassScope()548 AggregateDeclaration *Scope::getStructClassScope()
549 {
550     for (Scope *sc = this; sc; sc = sc->enclosing)
551     {
552         if (!sc->scopesym)
553             continue;
554 
555         AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
556         if (ad)
557             return ad;
558         ad = sc->scopesym->isStructDeclaration();
559         if (ad)
560             return ad;
561     }
562     return NULL;
563 }
564 
565 /*******************************************
566  * For TemplateDeclarations, we need to remember the Scope
567  * where it was declared. So mark the Scope as not
568  * to be free'd.
569  */
570 
setNoFree()571 void Scope::setNoFree()
572 {
573     //int i = 0;
574 
575     //printf("Scope::setNoFree(this = %p)\n", this);
576     for (Scope *sc = this; sc; sc = sc->enclosing)
577     {
578         //printf("\tsc = %p\n", sc);
579         sc->nofree = 1;
580 
581         assert(!(flags & SCOPEfree));
582         //assert(sc != sc->enclosing);
583         //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
584         //if (++i == 10)
585             //assert(0);
586     }
587 }
588 
alignment()589 structalign_t Scope::alignment()
590 {
591     if (aligndecl)
592         return aligndecl->getAlignment(this);
593     else
594         return STRUCTALIGN_DEFAULT;
595 }
596 
597 /************************************************
598  * Given the failed search attempt, try to find
599  * one with a close spelling.
600  */
601 
scope_search_fp(void * arg,const char * seed,int * cost)602 void *scope_search_fp(void *arg, const char *seed, int* cost)
603 {
604     //printf("scope_search_fp('%s')\n", seed);
605 
606     /* If not in the lexer's string table, it certainly isn't in the symbol table.
607      * Doing this first is a lot faster.
608      */
609     size_t len = strlen(seed);
610     if (!len)
611         return NULL;
612     Identifier *id = Identifier::lookup(seed, len);
613     if (!id)
614         return NULL;
615 
616     Scope *sc = (Scope *)arg;
617     Module::clearCache();
618     Dsymbol *scopesym = NULL;
619     Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
620     if (s)
621     {
622         for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
623             if (sc->scopesym == scopesym)
624                 break;
625         if (scopesym != s->parent)
626         {
627             (*cost)++; // got to the symbol through an import
628             if (s->prot().kind == PROTprivate)
629                 return NULL;
630         }
631     }
632     return (void*)s;
633 }
634 
deprecation10378(Loc loc,Dsymbol * sold,Dsymbol * snew)635 void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew)
636 {
637     // Bugzilla 15857
638     //
639     // The overloadset found via the new lookup rules is either
640     // equal or a subset of the overloadset found via the old
641     // lookup rules, so it suffices to compare the dimension to
642     // check for equality.
643     OverloadSet *osold = NULL;
644     OverloadSet *osnew = NULL;
645     if (sold && (osold = sold->isOverloadSet()) != NULL &&
646         snew && (osnew = snew->isOverloadSet()) != NULL &&
647         osold->a.dim == osnew->a.dim)
648         return;
649 
650     OutBuffer buf;
651     buf.writestring("local import search method found ");
652     if (osold)
653         buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim);
654     else if (sold)
655         buf.printf("%s %s", sold->kind(), sold->toPrettyChars());
656     else
657         buf.writestring("nothing");
658     buf.writestring(" instead of ");
659     if (osnew)
660         buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim);
661     else if (snew)
662         buf.printf("%s %s", snew->kind(), snew->toPrettyChars());
663     else
664         buf.writestring("nothing");
665 
666     deprecation(loc, "%s", buf.peekString());
667 }
668 
search_correct(Identifier * ident)669 Dsymbol *Scope::search_correct(Identifier *ident)
670 {
671     if (global.gag)
672         return NULL;            // don't do it for speculative compiles; too time consuming
673 
674     return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
675 }
676 
677 /************************************
678  * Maybe `ident` was a C or C++ name. Check for that,
679  * and suggest the D equivalent.
680  * Params:
681  *  ident = unknown identifier
682  * Returns:
683  *  D identifier string if found, null if not
684  */
search_correct_C(Identifier * ident)685 const char *Scope::search_correct_C(Identifier *ident)
686 {
687     TOK tok;
688     if (ident == Id::C_NULL)
689         tok = TOKnull;
690     else if (ident == Id::C_TRUE)
691         tok = TOKtrue;
692     else if (ident == Id::C_FALSE)
693         tok = TOKfalse;
694     else if (ident == Id::C_unsigned)
695         tok = TOKuns32;
696     else if (ident == Id::C_wchar_t)
697         tok = global.params.isWindows ? TOKwchar : TOKdchar;
698     else
699         return NULL;
700     return Token::toChars(tok);
701 }
702