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
29Scope *Scope::freelist = NULL;
30
31void allocFieldinit(Scope *sc, size_t dim)
32{
33    sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
34    sc->fieldinit_dim = dim;
35}
36
37void freeFieldinit(Scope *sc)
38{
39    if (sc->fieldinit)
40        mem.xfree(sc->fieldinit);
41    sc->fieldinit = NULL;
42    sc->fieldinit_dim = 0;
43}
44
45Scope *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
60Scope::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
104Scope *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
116Scope *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
147Scope *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
167Scope *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
175Scope *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
206Scope *Scope::startCTFE()
207{
208    Scope *sc = this->push();
209    sc->flags = this->flags | SCOPEctfe;
210    return sc;
211}
212
213Scope *Scope::endCTFE()
214{
215    assert(flags & SCOPEctfe);
216    return pop();
217}
218
219void 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
283unsigned *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
296static 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
346void 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
369Module *Scope::instantiatingModule()
370{
371    // TODO: in speculative context, returning 'module' is correct?
372    return minst ? minst : _module;
373}
374
375static 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 */
419Dsymbol *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
493Dsymbol *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
530ClassDeclaration *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
548AggregateDeclaration *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
571void 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
589structalign_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
602void *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
635void 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
669Dsymbol *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 */
685const 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