dsymbol.c revision 1.1.1.2
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/dsymbol.c
9 */
10
11#include "root/dsystem.h"
12#include "root/rmem.h"
13#include "root/speller.h"
14#include "root/aav.h"
15
16#include "mars.h"
17#include "dsymbol.h"
18#include "aggregate.h"
19#include "identifier.h"
20#include "module.h"
21#include "mtype.h"
22#include "expression.h"
23#include "statement.h"
24#include "declaration.h"
25#include "id.h"
26#include "scope.h"
27#include "init.h"
28#include "import.h"
29#include "template.h"
30#include "attrib.h"
31#include "enum.h"
32#include "lexer.h"
33#include "nspace.h"
34
35bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
36typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
37int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
38Expression *semantic(Expression *e, Scope *sc);
39
40
41/****************************** Dsymbol ******************************/
42
43Dsymbol::Dsymbol()
44{
45    //printf("Dsymbol::Dsymbol(%p)\n", this);
46    this->ident = NULL;
47    this->parent = NULL;
48    this->csym = NULL;
49    this->isym = NULL;
50    this->loc = Loc();
51    this->comment = NULL;
52    this->_scope = NULL;
53    this->prettystring = NULL;
54    this->semanticRun = PASSinit;
55    this->errors = false;
56    this->depdecl = NULL;
57    this->userAttribDecl = NULL;
58    this->ddocUnittest = NULL;
59}
60
61Dsymbol::Dsymbol(Identifier *ident)
62{
63    //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
64    this->ident = ident;
65    this->parent = NULL;
66    this->csym = NULL;
67    this->isym = NULL;
68    this->loc = Loc();
69    this->comment = NULL;
70    this->_scope = NULL;
71    this->prettystring = NULL;
72    this->semanticRun = PASSinit;
73    this->errors = false;
74    this->depdecl = NULL;
75    this->userAttribDecl = NULL;
76    this->ddocUnittest = NULL;
77}
78
79Dsymbol *Dsymbol::create(Identifier *ident)
80{
81    return new Dsymbol(ident);
82}
83
84bool Dsymbol::equals(RootObject *o)
85{
86    if (this == o)
87        return true;
88    Dsymbol *s = (Dsymbol *)(o);
89    // Overload sets don't have an ident
90    if (s && ident && s->ident && ident->equals(s->ident))
91        return true;
92    return false;
93}
94
95/**************************************
96 * Copy the syntax.
97 * Used for template instantiations.
98 * If s is NULL, allocate the new object, otherwise fill it in.
99 */
100
101Dsymbol *Dsymbol::syntaxCopy(Dsymbol *)
102{
103    print();
104    printf("%s %s\n", kind(), toChars());
105    assert(0);
106    return NULL;
107}
108
109/**************************************
110 * Determine if this symbol is only one.
111 * Returns:
112 *      false, *ps = NULL: There are 2 or more symbols
113 *      true,  *ps = NULL: There are zero symbols
114 *      true,  *ps = symbol: The one and only one symbol
115 */
116
117bool Dsymbol::oneMember(Dsymbol **ps, Identifier *)
118{
119    //printf("Dsymbol::oneMember()\n");
120    *ps = this;
121    return true;
122}
123
124/*****************************************
125 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
126 */
127
128bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident)
129{
130    //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0);
131    Dsymbol *s = NULL;
132
133    if (members)
134    {
135        for (size_t i = 0; i < members->dim; i++)
136        {
137            Dsymbol *sx = (*members)[i];
138            bool x = sx->oneMember(ps, ident);
139            //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
140            if (!x)
141            {
142                //printf("\tfalse 1\n");
143                assert(*ps == NULL);
144                return false;
145            }
146            if (*ps)
147            {
148                assert(ident);
149                if (!(*ps)->ident || !(*ps)->ident->equals(ident))
150                    continue;
151                if (!s)
152                    s = *ps;
153                else if (s->isOverloadable() && (*ps)->isOverloadable())
154                {
155                    // keep head of overload set
156                    FuncDeclaration *f1 = s->isFuncDeclaration();
157                    FuncDeclaration *f2 = (*ps)->isFuncDeclaration();
158                    if (f1 && f2)
159                    {
160                        assert(!f1->isFuncAliasDeclaration());
161                        assert(!f2->isFuncAliasDeclaration());
162                        for (; f1 != f2; f1 = f1->overnext0)
163                        {
164                            if (f1->overnext0 == NULL)
165                            {
166                                f1->overnext0 = f2;
167                                break;
168                            }
169                        }
170                    }
171                }
172                else                    // more than one symbol
173                {
174                    *ps = NULL;
175                    //printf("\tfalse 2\n");
176                    return false;
177                }
178            }
179        }
180    }
181    *ps = s;            // s is the one symbol, NULL if none
182    //printf("\ttrue\n");
183    return true;
184}
185
186/*****************************************
187 * Is Dsymbol a variable that contains pointers?
188 */
189
190bool Dsymbol::hasPointers()
191{
192    //printf("Dsymbol::hasPointers() %s\n", toChars());
193    return false;
194}
195
196bool Dsymbol::hasStaticCtorOrDtor()
197{
198    //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
199    return false;
200}
201
202void Dsymbol::setFieldOffset(AggregateDeclaration *, unsigned *, bool)
203{
204}
205
206Identifier *Dsymbol::getIdent()
207{
208    return ident;
209}
210
211const char *Dsymbol::toChars()
212{
213    return ident ? ident->toChars() : "__anonymous";
214}
215
216const char *Dsymbol::toPrettyCharsHelper()
217{
218    return toChars();
219}
220
221const char *Dsymbol::toPrettyChars(bool QualifyTypes)
222{
223    if (prettystring && !QualifyTypes)
224        return (const char *)prettystring;
225
226    //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
227    if (!parent)
228    {
229        const char *s = toChars();
230        if (!QualifyTypes)
231            prettystring = (const utf8_t *)s;
232        return s;
233    }
234
235    // Computer number of components
236    size_t complength = 0;
237    for (Dsymbol *p = this; p; p = p->parent)
238        ++complength;
239
240    // Allocate temporary array comp[]
241    const char **comp = (const char **)mem.xmalloc(complength * sizeof(char**));
242
243    // Fill in comp[] and compute length of final result
244    size_t length = 0;
245    int i = 0;
246    for (Dsymbol *p = this; p; p = p->parent)
247    {
248        const char *s = QualifyTypes ? p->toPrettyCharsHelper() : p->toChars();
249        const size_t len = strlen(s);
250        comp[i] = s;
251        ++i;
252        length += len + 1;
253    }
254
255    char *s = (char *)mem.xmalloc(length);
256    char *q = s + length - 1;
257    *q = 0;
258    for (size_t j = 0; j < complength; j++)
259    {
260        const char *t = comp[j];
261        const size_t len = strlen(t);
262        q -= len;
263        memcpy(q, t, len);
264        if (q == s)
265            break;
266        *--q = '.';
267    }
268    free(comp);
269    if (!QualifyTypes)
270        prettystring = (utf8_t *)s;
271    return s;
272}
273
274Loc& Dsymbol::getLoc()
275{
276    if (!loc.filename)  // avoid bug 5861.
277    {
278        Module *m = getModule();
279
280        if (m && m->srcfile)
281            loc.filename = m->srcfile->toChars();
282    }
283    return loc;
284}
285
286const char *Dsymbol::locToChars()
287{
288    return getLoc().toChars();
289}
290
291const char *Dsymbol::kind() const
292{
293    return "symbol";
294}
295
296/*********************************
297 * If this symbol is really an alias for another,
298 * return that other.
299 * If needed, semantic() is invoked due to resolve forward reference.
300 */
301Dsymbol *Dsymbol::toAlias()
302{
303    return this;
304}
305
306/*********************************
307 * Resolve recursive tuple expansion in eponymous template.
308 */
309Dsymbol *Dsymbol::toAlias2()
310{
311    return toAlias();
312}
313
314/**
315 * `pastMixin` returns the enclosing symbol if this is a template mixin.
316 *
317 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
318 * are mangleOnly.
319 *
320 * See also `parent`, `toParent`, `toParent2` and `toParent3`.
321 */
322Dsymbol *Dsymbol::pastMixin()
323{
324    //printf("Dsymbol::pastMixin() %s\n", toChars());
325    if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
326        return this;
327    if (!parent)
328        return NULL;
329    return parent->pastMixin();
330}
331
332/// ditto
333Dsymbol *Dsymbol::pastMixinAndNspace()
334{
335    //printf("Dsymbol::pastMixinAndNspace() %s\n", toChars());
336    Nspace *ns = isNspace();
337    if (!(ns && ns->mangleOnly) &&
338        !isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
339        return this;
340    if (!parent)
341        return NULL;
342    return parent->pastMixinAndNspace();
343}
344
345/**********************************
346 * `parent` field returns a lexically enclosing scope symbol this is a member of.
347 *
348 * `toParent()` returns a logically enclosing scope symbol this is a member of.
349 * It skips over TemplateMixin's and Nspaces that are mangleOnly.
350 *
351 * `toParent2()` returns an enclosing scope symbol this is living at runtime.
352 * It skips over both TemplateInstance's and TemplateMixin's.
353 * It's used when looking for the 'this' pointer of the enclosing function/class.
354 *
355 * `toParent3()` returns a logically enclosing scope symbol this is a member of.
356 * It skips over TemplateMixin's.
357 *
358 * Examples:
359 *  module mod;
360 *  template Foo(alias a) { mixin Bar!(); }
361 *  mixin template Bar() {
362 *    public {  // ProtDeclaration
363 *      void baz() { a = 2; }
364 *    }
365 *  }
366 *  void test() {
367 *    int v = 1;
368 *    alias foo = Foo!(v);
369 *    foo.baz();
370 *    assert(v == 2);
371 *  }
372 *
373 *  // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
374 *  // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
375 *  // s.toParent() == TemplateInstance('mod.test.Foo!()')
376 *  // s.toParent2() == FuncDeclaration('mod.test')
377 */
378Dsymbol *Dsymbol::toParent()
379{
380    return parent ? parent->pastMixinAndNspace() : NULL;
381}
382
383/// ditto
384Dsymbol *Dsymbol::toParent2()
385{
386    if (!parent ||
387        (!parent->isTemplateInstance() &&
388         !parent->isForwardingAttribDeclaration() &&
389         !parent->isForwardingScopeDsymbol()))
390        return parent;
391    return parent->toParent2();
392}
393
394/// ditto
395Dsymbol *Dsymbol::toParent3()
396{
397    return parent ? parent->pastMixin() : NULL;
398}
399
400TemplateInstance *Dsymbol::isInstantiated()
401{
402    for (Dsymbol *s = parent; s; s = s->parent)
403    {
404        TemplateInstance *ti = s->isTemplateInstance();
405        if (ti && !ti->isTemplateMixin())
406            return ti;
407    }
408    return NULL;
409}
410
411// Check if this function is a member of a template which has only been
412// instantiated speculatively, eg from inside is(typeof()).
413// Return the speculative template instance it is part of,
414// or NULL if not speculative.
415TemplateInstance *Dsymbol::isSpeculative()
416{
417    Dsymbol *par = parent;
418    while (par)
419    {
420        TemplateInstance *ti = par->isTemplateInstance();
421        if (ti && ti->gagged)
422            return ti;
423        par = par->toParent();
424    }
425    return NULL;
426}
427
428Ungag Dsymbol::ungagSpeculative()
429{
430    unsigned oldgag = global.gag;
431
432    if (global.gag && !isSpeculative() && !toParent2()->isFuncDeclaration())
433        global.gag = 0;
434
435    return Ungag(oldgag);
436}
437
438bool Dsymbol::isAnonymous()
439{
440    return ident == NULL;
441}
442
443/*************************************
444 * Set scope for future semantic analysis so we can
445 * deal better with forward references.
446 */
447
448void Dsymbol::setScope(Scope *sc)
449{
450    //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
451    if (!sc->nofree)
452        sc->setNoFree();                // may need it even after semantic() finishes
453    _scope = sc;
454    if (sc->depdecl)
455        depdecl = sc->depdecl;
456
457    if (!userAttribDecl)
458        userAttribDecl = sc->userAttribDecl;
459}
460
461void Dsymbol::importAll(Scope *)
462{
463}
464
465/*************************************
466 * Does semantic analysis on the public face of declarations.
467 */
468
469void Dsymbol::semantic(Scope *)
470{
471    error("%p has no semantic routine", this);
472}
473
474/*************************************
475 * Does semantic analysis on initializers and members of aggregates.
476 */
477
478void Dsymbol::semantic2(Scope *)
479{
480    // Most Dsymbols have no further semantic analysis needed
481}
482
483/*************************************
484 * Does semantic analysis on function bodies.
485 */
486
487void Dsymbol::semantic3(Scope *)
488{
489    // Most Dsymbols have no further semantic analysis needed
490}
491
492/*********************************************
493 * Search for ident as member of s.
494 * Params:
495 *  loc = location to print for error messages
496 *  ident = identifier to search for
497 *  flags = IgnoreXXXX
498 * Returns:
499 *  NULL if not found
500 */
501
502Dsymbol *Dsymbol::search(const Loc &, Identifier *, int)
503{
504    //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
505    return NULL;
506}
507
508/***************************************************
509 * Search for symbol with correct spelling.
510 */
511
512void *symbol_search_fp(void *arg, const char *seed, int *cost)
513{
514    /* If not in the lexer's string table, it certainly isn't in the symbol table.
515     * Doing this first is a lot faster.
516     */
517    size_t len = strlen(seed);
518    if (!len)
519        return NULL;
520    Identifier *id = Identifier::lookup(seed, len);
521    if (!id)
522        return NULL;
523
524    *cost = 0;
525    Dsymbol *s = (Dsymbol *)arg;
526    Module::clearCache();
527    return (void *)s->search(Loc(), id, IgnoreErrors);
528}
529
530Dsymbol *Dsymbol::search_correct(Identifier *ident)
531{
532    if (global.gag)
533        return NULL;            // don't do it for speculative compiles; too time consuming
534
535    return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars);
536}
537
538/***************************************
539 * Search for identifier id as a member of 'this'.
540 * id may be a template instance.
541 * Returns:
542 *      symbol found, NULL if not
543 */
544Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
545{
546    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
547    Dsymbol *s = toAlias();
548    Dsymbol *sm;
549
550    if (Declaration *d = s->isDeclaration())
551    {
552        if (d->inuse)
553        {
554            ::error(loc, "circular reference to '%s'", d->toPrettyChars());
555            return NULL;
556        }
557    }
558
559    switch (id->dyncast())
560    {
561        case DYNCAST_IDENTIFIER:
562            sm = s->search(loc, (Identifier *)id);
563            break;
564
565        case DYNCAST_DSYMBOL:
566        {
567            // It's a template instance
568            //printf("\ttemplate instance id\n");
569            Dsymbol *st = (Dsymbol *)id;
570            TemplateInstance *ti = st->isTemplateInstance();
571            sm = s->search(loc, ti->name);
572            if (!sm)
573            {
574                sm = s->search_correct(ti->name);
575                if (sm)
576                    ::error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?",
577                          ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars());
578                else
579                    ::error(loc, "template identifier '%s' is not a member of %s '%s'",
580                          ti->name->toChars(), s->kind(), s->toPrettyChars());
581                return NULL;
582            }
583            sm = sm->toAlias();
584            TemplateDeclaration *td = sm->isTemplateDeclaration();
585            if (!td)
586            {
587                ::error(loc, "%s.%s is not a template, it is a %s", s->toPrettyChars(), ti->name->toChars(), sm->kind());
588                return NULL;
589            }
590            ti->tempdecl = td;
591            if (!ti->semanticRun)
592                ti->semantic(sc);
593            sm = ti->toAlias();
594            break;
595        }
596
597        case DYNCAST_TYPE:
598        case DYNCAST_EXPRESSION:
599        default:
600            assert(0);
601    }
602    return sm;
603}
604
605bool Dsymbol::overloadInsert(Dsymbol *)
606{
607    //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
608    return false;
609}
610
611d_uns64 Dsymbol::size(Loc)
612{
613    error("Dsymbol '%s' has no size", toChars());
614    return SIZE_INVALID;
615}
616
617bool Dsymbol::isforwardRef()
618{
619    return false;
620}
621
622AggregateDeclaration *Dsymbol::isThis()
623{
624    return NULL;
625}
626
627bool Dsymbol::isExport() const
628{
629    return false;
630}
631
632bool Dsymbol::isImportedSymbol() const
633{
634    return false;
635}
636
637bool Dsymbol::isDeprecated()
638{
639    return false;
640}
641
642bool Dsymbol::isOverloadable()
643{
644    return false;
645}
646
647LabelDsymbol *Dsymbol::isLabel()                // is this a LabelDsymbol()?
648{
649    return NULL;
650}
651
652/// Returns an AggregateDeclaration when toParent() is that.
653AggregateDeclaration *Dsymbol::isMember()
654{
655    //printf("Dsymbol::isMember() %s\n", toChars());
656    Dsymbol *parent = toParent();
657    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
658    return parent ? parent->isAggregateDeclaration() : NULL;
659}
660
661/// Returns an AggregateDeclaration when toParent2() is that.
662AggregateDeclaration *Dsymbol::isMember2()
663{
664    //printf("Dsymbol::isMember2() %s\n", toChars());
665    Dsymbol *parent = toParent2();
666    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
667    return parent ? parent->isAggregateDeclaration() : NULL;
668}
669
670// is this a member of a ClassDeclaration?
671ClassDeclaration *Dsymbol::isClassMember()
672{
673    AggregateDeclaration *ad = isMember();
674    return ad ? ad->isClassDeclaration() : NULL;
675}
676
677Type *Dsymbol::getType()
678{
679    return NULL;
680}
681
682bool Dsymbol::needThis()
683{
684    return false;
685}
686
687/*********************************
688 * Iterate this dsymbol or members of this scoped dsymbol, then
689 * call `fp` with the found symbol and `param`.
690 * Params:
691 *  fp = function pointer to process the iterated symbol.
692 *       If it returns nonzero, the iteration will be aborted.
693 *  param = a parameter passed to fp.
694 * Returns:
695 *  nonzero if the iteration is aborted by the return value of fp,
696 *  or 0 if it's completed.
697 */
698int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
699{
700    return (*fp)(this, param);
701}
702
703void Dsymbol::addMember(Scope *, ScopeDsymbol *sds)
704{
705    //printf("Dsymbol::addMember('%s')\n", toChars());
706    //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars());
707    //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab);
708    parent = sds;
709    if (!isAnonymous())         // no name, so can't add it to symbol table
710    {
711        if (!sds->symtabInsert(this))    // if name is already defined
712        {
713            Dsymbol *s2 = sds->symtabLookup(this, ident);
714            if (!s2->overloadInsert(this))
715            {
716                sds->multiplyDefined(Loc(), this, s2);
717                errors = true;
718            }
719        }
720        if (sds->isAggregateDeclaration() || sds->isEnumDeclaration())
721        {
722            if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
723            {
724                error(".%s property cannot be redefined", ident->toChars());
725                errors = true;
726            }
727        }
728    }
729}
730
731void Dsymbol::error(const char *format, ...)
732{
733    va_list ap;
734    va_start(ap, format);
735    ::verror(getLoc(), format, ap, kind(), toPrettyChars());
736    va_end(ap);
737}
738
739void Dsymbol::error(Loc loc, const char *format, ...)
740{
741    va_list ap;
742    va_start(ap, format);
743    ::verror(loc, format, ap, kind(), toPrettyChars());
744    va_end(ap);
745}
746
747void Dsymbol::deprecation(Loc loc, const char *format, ...)
748{
749    va_list ap;
750    va_start(ap, format);
751    ::vdeprecation(loc, format, ap, kind(), toPrettyChars());
752    va_end(ap);
753}
754
755void Dsymbol::deprecation(const char *format, ...)
756{
757    va_list ap;
758    va_start(ap, format);
759    ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars());
760    va_end(ap);
761}
762
763void Dsymbol::checkDeprecated(Loc loc, Scope *sc)
764{
765    if (global.params.useDeprecated != DIAGNOSTICoff && isDeprecated())
766    {
767        // Don't complain if we're inside a deprecated symbol's scope
768        for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
769        {
770            if (sp->isDeprecated())
771                goto L1;
772        }
773
774        for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
775        {
776            if (sc2->scopesym && sc2->scopesym->isDeprecated())
777                goto L1;
778
779            // If inside a StorageClassDeclaration that is deprecated
780            if (sc2->stc & STCdeprecated)
781                goto L1;
782        }
783
784        const char *message = NULL;
785        for (Dsymbol *p = this; p; p = p->parent)
786        {
787            message = p->depdecl ? p->depdecl->getMessage() : NULL;
788            if (message)
789                break;
790        }
791
792        if (message)
793            deprecation(loc, "is deprecated - %s", message);
794        else
795            deprecation(loc, "is deprecated");
796    }
797
798  L1:
799    Declaration *d = isDeclaration();
800    if (d && d->storage_class & STCdisable)
801    {
802        if (!(sc->func && sc->func->storage_class & STCdisable))
803        {
804            if (d->toParent() && d->isPostBlitDeclaration())
805                d->toParent()->error(loc, "is not copyable because it is annotated with @disable");
806            else
807                error(loc, "is not callable because it is annotated with @disable");
808        }
809    }
810}
811
812/**********************************
813 * Determine which Module a Dsymbol is in.
814 */
815
816Module *Dsymbol::getModule()
817{
818    //printf("Dsymbol::getModule()\n");
819    if (TemplateInstance *ti = isInstantiated())
820        return ti->tempdecl->getModule();
821
822    Dsymbol *s = this;
823    while (s)
824    {
825        //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
826        Module *m = s->isModule();
827        if (m)
828            return m;
829        s = s->parent;
830    }
831    return NULL;
832}
833
834/**********************************
835 * Determine which Module a Dsymbol is in, as far as access rights go.
836 */
837
838Module *Dsymbol::getAccessModule()
839{
840    //printf("Dsymbol::getAccessModule()\n");
841    if (TemplateInstance *ti = isInstantiated())
842        return ti->tempdecl->getAccessModule();
843
844    Dsymbol *s = this;
845    while (s)
846    {
847        //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
848        Module *m = s->isModule();
849        if (m)
850            return m;
851        TemplateInstance *ti = s->isTemplateInstance();
852        if (ti && ti->enclosing)
853        {
854            /* Because of local template instantiation, the parent isn't where the access
855             * rights come from - it's the template declaration
856             */
857            s = ti->tempdecl;
858        }
859        else
860            s = s->parent;
861    }
862    return NULL;
863}
864
865/*************************************
866 */
867
868Prot Dsymbol::prot()
869{
870    return Prot(PROTpublic);
871}
872
873/*************************************
874 * Do syntax copy of an array of Dsymbol's.
875 */
876
877Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a)
878{
879
880    Dsymbols *b = NULL;
881    if (a)
882    {
883        b = a->copy();
884        for (size_t i = 0; i < b->dim; i++)
885        {
886            (*b)[i] = (*b)[i]->syntaxCopy(NULL);
887        }
888    }
889    return b;
890}
891
892/****************************************
893 * Add documentation comment to Dsymbol.
894 * Ignore NULL comments.
895 */
896
897void Dsymbol::addComment(const utf8_t *comment)
898{
899    //if (comment)
900        //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
901
902    if (!this->comment)
903        this->comment = comment;
904    else if (comment && strcmp((const char *)comment, (const char *)this->comment) != 0)
905    {   // Concatenate the two
906        this->comment = Lexer::combineComments(this->comment, comment);
907    }
908}
909
910/****************************************
911 * Returns true if this symbol is defined in a non-root module without instantiation.
912 */
913bool Dsymbol::inNonRoot()
914{
915    Dsymbol *s = parent;
916    for (; s; s = s->toParent())
917    {
918        if (s->isTemplateInstance())
919        {
920            return false;
921        }
922        if (Module *m = s->isModule())
923        {
924            if (!m->isRoot())
925                return true;
926            break;
927        }
928    }
929    return false;
930}
931
932/********************************* OverloadSet ****************************/
933
934OverloadSet::OverloadSet(Identifier *ident, OverloadSet *os)
935    : Dsymbol(ident)
936{
937    if (os)
938    {
939        for (size_t i = 0; i < os->a.dim; i++)
940        {
941            a.push(os->a[i]);
942        }
943    }
944}
945
946void OverloadSet::push(Dsymbol *s)
947{
948    a.push(s);
949}
950
951const char *OverloadSet::kind() const
952{
953    return "overloadset";
954}
955
956
957/********************************* ForwardingScopeDsymbol ******************/
958
959ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol *forward)
960    : ScopeDsymbol()
961{
962    this->forward = forward;
963}
964
965Dsymbol *ForwardingScopeDsymbol::symtabInsert(Dsymbol *s)
966{
967    assert(forward);
968    if (Declaration *d = s->isDeclaration())
969    {
970        if (d->storage_class & STClocal)
971        {
972            // Symbols with storage class STClocal are not
973            // forwarded, but stored in the local symbol
974            // table. (Those are the `static foreach` variables.)
975            if (!symtab)
976            {
977                symtab = new DsymbolTable();
978            }
979            return ScopeDsymbol::symtabInsert(s); // insert locally
980        }
981    }
982    if (!forward->symtab)
983    {
984        forward->symtab = new DsymbolTable();
985    }
986    // Non-STClocal symbols are forwarded to `forward`.
987    return forward->symtabInsert(s);
988}
989
990/************************
991 * This override handles the following two cases:
992 *     static foreach (i, i; [0]) { ... }
993 * and
994 *     static foreach (i; [0]) { enum i = 2; }
995 */
996Dsymbol *ForwardingScopeDsymbol::symtabLookup(Dsymbol *s, Identifier *id)
997{
998    assert(forward);
999    // correctly diagnose clashing foreach loop variables.
1000    if (Declaration *d = s->isDeclaration())
1001    {
1002        if (d->storage_class & STClocal)
1003        {
1004            if (!symtab)
1005            {
1006                symtab = new DsymbolTable();
1007            }
1008            return ScopeDsymbol::symtabLookup(s,id);
1009        }
1010    }
1011    // Declarations within `static foreach` do not clash with
1012    // `static foreach` loop variables.
1013    if (!forward->symtab)
1014    {
1015        forward->symtab = new DsymbolTable();
1016    }
1017    return forward->symtabLookup(s,id);
1018}
1019
1020void ForwardingScopeDsymbol::importScope(Dsymbol *s, Prot protection)
1021{
1022    forward->importScope(s, protection);
1023}
1024
1025void ForwardingScopeDsymbol::semantic(Scope *)
1026{
1027}
1028
1029const char *ForwardingScopeDsymbol::kind() const
1030{
1031    return "local scope";
1032}
1033
1034/********************************* ScopeDsymbol ****************************/
1035
1036ScopeDsymbol::ScopeDsymbol()
1037    : Dsymbol()
1038{
1039    members = NULL;
1040    symtab = NULL;
1041    endlinnum = 0;
1042    importedScopes = NULL;
1043    prots = NULL;
1044}
1045
1046ScopeDsymbol::ScopeDsymbol(Identifier *id)
1047    : Dsymbol(id)
1048{
1049    members = NULL;
1050    symtab = NULL;
1051    endlinnum = 0;
1052    importedScopes = NULL;
1053    prots = NULL;
1054}
1055
1056Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
1057{
1058    //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1059    ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident);
1060    sds->members = arraySyntaxCopy(members);
1061    sds->endlinnum = endlinnum;
1062    return sds;
1063}
1064
1065void ScopeDsymbol::semantic(Scope *)
1066{
1067}
1068
1069/*****************************************
1070 * This function is #1 on the list of functions that eat cpu time.
1071 * Be very, very careful about slowing it down.
1072 */
1073
1074Dsymbol *ScopeDsymbol::search(const Loc &loc, Identifier *ident, int flags)
1075{
1076    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
1077    //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;
1078
1079    // Look in symbols declared in this module
1080    if (symtab && !(flags & SearchImportsOnly))
1081    {
1082        //printf(" look in locals\n");
1083        Dsymbol *s1 = symtab->lookup(ident);
1084        if (s1)
1085        {
1086            //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars());
1087            return s1;
1088        }
1089    }
1090    //printf(" not found in locals\n");
1091
1092    // Look in imported scopes
1093    if (importedScopes)
1094    {
1095        //printf(" look in imports\n");
1096        Dsymbol *s = NULL;
1097        OverloadSet *a = NULL;
1098
1099        // Look in imported modules
1100        for (size_t i = 0; i < importedScopes->dim; i++)
1101        {
1102            // If private import, don't search it
1103            if ((flags & IgnorePrivateImports) && prots[i] == PROTprivate)
1104                continue;
1105
1106            int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches
1107            Dsymbol *ss = (*importedScopes)[i];
1108
1109            //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
1110
1111            if (ss->isModule())
1112            {
1113                if (flags & SearchLocalsOnly)
1114                    continue;
1115            }
1116            else // mixin template
1117            {
1118                if (flags & SearchImportsOnly)
1119                    continue;
1120                // compatibility with -transition=import (Bugzilla 15925)
1121                // SearchLocalsOnly should always get set for new lookup rules
1122                sflags |= (flags & SearchLocalsOnly);
1123            }
1124
1125            /* Don't find private members if ss is a module
1126             */
1127            Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateImports : IgnoreNone));
1128            if (!s2 || (!(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)))
1129                continue;
1130            if (!s)
1131            {
1132                s = s2;
1133                if (s && s->isOverloadSet())
1134                    a = mergeOverloadSet(ident, a, s);
1135            }
1136            else if (s2 && s != s2)
1137            {
1138                if (s->toAlias() == s2->toAlias() ||
1139                    (s->getType() == s2->getType() && s->getType()))
1140                {
1141                    /* After following aliases, we found the same
1142                     * symbol, so it's not an ambiguity.  But if one
1143                     * alias is deprecated or less accessible, prefer
1144                     * the other.
1145                     */
1146                    if (s->isDeprecated() ||
1147                        (s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != PROTnone))
1148                        s = s2;
1149                }
1150                else
1151                {
1152                    /* Two imports of the same module should be regarded as
1153                     * the same.
1154                     */
1155                    Import *i1 = s->isImport();
1156                    Import *i2 = s2->isImport();
1157                    if (!(i1 && i2 &&
1158                          (i1->mod == i2->mod ||
1159                           (!i1->parent->isImport() && !i2->parent->isImport() &&
1160                            i1->ident->equals(i2->ident))
1161                          )
1162                         )
1163                       )
1164                    {
1165                        /* Bugzilla 8668:
1166                         * Public selective import adds AliasDeclaration in module.
1167                         * To make an overload set, resolve aliases in here and
1168                         * get actual overload roots which accessible via s and s2.
1169                         */
1170                        s = s->toAlias();
1171                        s2 = s2->toAlias();
1172
1173                        /* If both s2 and s are overloadable (though we only
1174                         * need to check s once)
1175                         */
1176                        if ((s2->isOverloadSet() || s2->isOverloadable()) &&
1177                            (a || s->isOverloadable()))
1178                        {
1179                            a = mergeOverloadSet(ident, a, s2);
1180                            continue;
1181                        }
1182                        if (flags & IgnoreAmbiguous)    // if return NULL on ambiguity
1183                            return NULL;
1184                        if (!(flags & IgnoreErrors))
1185                            ScopeDsymbol::multiplyDefined(loc, s, s2);
1186                        break;
1187                    }
1188                }
1189            }
1190        }
1191
1192        if (s)
1193        {
1194            /* Build special symbol if we had multiple finds
1195             */
1196            if (a)
1197            {
1198                if (!s->isOverloadSet())
1199                    a = mergeOverloadSet(ident, a, s);
1200                s = a;
1201            }
1202
1203            // TODO: remove once private symbol visibility has been deprecated
1204            if (!(flags & IgnoreErrors) && s->prot().kind == PROTprivate &&
1205                !s->isOverloadable() && !s->parent->isTemplateMixin() && !s->parent->isNspace())
1206            {
1207                AliasDeclaration *ad;
1208                // accessing private selective and renamed imports is
1209                // deprecated by restricting the symbol visibility
1210                if (s->isImport() || ((ad = s->isAliasDeclaration()) != NULL && ad->_import != NULL))
1211                {}
1212                else
1213                    error(loc, "%s %s is private", s->kind(), s->toPrettyChars());
1214            }
1215            //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1216            return s;
1217        }
1218        //printf(" not found in imports\n");
1219    }
1220
1221    return NULL;
1222}
1223
1224OverloadSet *ScopeDsymbol::mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s)
1225{
1226    if (!os)
1227    {
1228        os = new OverloadSet(ident);
1229        os->parent = this;
1230    }
1231    if (OverloadSet *os2 = s->isOverloadSet())
1232    {
1233        // Merge the cross-module overload set 'os2' into 'os'
1234        if (os->a.dim == 0)
1235        {
1236            os->a.setDim(os2->a.dim);
1237            memcpy(os->a.tdata(), os2->a.tdata(), sizeof(os->a[0]) * os2->a.dim);
1238        }
1239        else
1240        {
1241            for (size_t i = 0; i < os2->a.dim; i++)
1242            {
1243                os = mergeOverloadSet(ident, os, os2->a[i]);
1244            }
1245        }
1246    }
1247    else
1248    {
1249        assert(s->isOverloadable());
1250
1251        /* Don't add to os[] if s is alias of previous sym
1252         */
1253        for (size_t j = 0; j < os->a.dim; j++)
1254        {
1255            Dsymbol *s2 = os->a[j];
1256            if (s->toAlias() == s2->toAlias())
1257            {
1258                if (s2->isDeprecated() ||
1259                    (s2->prot().isMoreRestrictiveThan(s->prot()) &&
1260                     s->prot().kind != PROTnone))
1261                {
1262                    os->a[j] = s;
1263                }
1264                goto Lcontinue;
1265            }
1266        }
1267        os->push(s);
1268    Lcontinue:
1269        ;
1270    }
1271    return os;
1272}
1273
1274void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
1275{
1276    //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
1277
1278    // No circular or redundant import's
1279    if (s != this)
1280    {
1281        if (!importedScopes)
1282            importedScopes = new Dsymbols();
1283        else
1284        {
1285            for (size_t i = 0; i < importedScopes->dim; i++)
1286            {
1287                Dsymbol *ss = (*importedScopes)[i];
1288                if (ss == s)                    // if already imported
1289                {
1290                    if (protection.kind > prots[i])
1291                        prots[i] = protection.kind;  // upgrade access
1292                    return;
1293                }
1294            }
1295        }
1296        importedScopes->push(s);
1297        prots = (PROTKIND *)mem.xrealloc(prots, importedScopes->dim * sizeof(prots[0]));
1298        prots[importedScopes->dim - 1] = protection.kind;
1299    }
1300}
1301
1302#define BITS_PER_INDEX (sizeof(size_t) * CHAR_BIT)
1303
1304static void bitArraySet(BitArray *array, size_t idx)
1305{
1306    array->ptr[idx / BITS_PER_INDEX] |= 1ULL << (idx % BITS_PER_INDEX);
1307}
1308
1309static bool bitArrayGet(BitArray *array, size_t idx)
1310{
1311    const size_t boffset = idx % BITS_PER_INDEX;
1312    return (array->ptr[idx / BITS_PER_INDEX] & (1ULL << boffset)) >> boffset;
1313}
1314
1315static void bitArrayLength(BitArray *array, size_t len)
1316{
1317    if (array->len < len)
1318    {
1319        const size_t obytes = (array->len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
1320        const size_t nbytes = (len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
1321
1322        if (!array->ptr)
1323            array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t));
1324        else
1325            array->ptr = (size_t *)mem.xrealloc(array->ptr, nbytes * sizeof(size_t));
1326
1327        for (size_t i = obytes; i < nbytes; i++)
1328            array->ptr[i] = 0;
1329
1330        array->len = nbytes * BITS_PER_INDEX;
1331    }
1332}
1333
1334void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection)
1335{
1336    BitArray *pary = protection.kind == PROTprivate ? &privateAccessiblePackages : &accessiblePackages;
1337    if (pary->len <= p->tag)
1338        bitArrayLength(pary, p->tag + 1);
1339    bitArraySet(pary, p->tag);
1340}
1341
1342bool ScopeDsymbol::isPackageAccessible(Package *p, Prot protection, int)
1343{
1344    if ((p->tag < accessiblePackages.len && bitArrayGet(&accessiblePackages, p->tag)) ||
1345        (protection.kind == PROTprivate && p->tag < privateAccessiblePackages.len && bitArrayGet(&privateAccessiblePackages, p->tag)))
1346        return true;
1347    if (importedScopes)
1348    {
1349        for (size_t i = 0; i < importedScopes->dim; i++)
1350        {
1351            // only search visible scopes && imported modules should ignore private imports
1352            Dsymbol *ss = (*importedScopes)[i];
1353            if (protection.kind <= prots[i] &&
1354                ss->isScopeDsymbol()->isPackageAccessible(p, protection, IgnorePrivateImports))
1355                return true;
1356        }
1357    }
1358    return false;
1359}
1360
1361bool ScopeDsymbol::isforwardRef()
1362{
1363    return (members == NULL);
1364}
1365
1366void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
1367{
1368    if (loc.filename)
1369    {   ::error(loc, "%s at %s conflicts with %s at %s",
1370            s1->toPrettyChars(),
1371            s1->locToChars(),
1372            s2->toPrettyChars(),
1373            s2->locToChars());
1374    }
1375    else
1376    {
1377        s1->error(s1->loc, "conflicts with %s %s at %s",
1378            s2->kind(),
1379            s2->toPrettyChars(),
1380            s2->locToChars());
1381    }
1382}
1383
1384const char *ScopeDsymbol::kind() const
1385{
1386    return "ScopeDsymbol";
1387}
1388
1389Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s)
1390{
1391    return symtab->insert(s);
1392}
1393
1394/****************************************
1395 * Look up identifier in symbol table.
1396 */
1397
1398Dsymbol *ScopeDsymbol::symtabLookup(Dsymbol *, Identifier *id)
1399{
1400    return symtab->lookup(id);
1401}
1402
1403/****************************************
1404 * Return true if any of the members are static ctors or static dtors, or if
1405 * any members have members that are.
1406 */
1407
1408bool ScopeDsymbol::hasStaticCtorOrDtor()
1409{
1410    if (members)
1411    {
1412        for (size_t i = 0; i < members->dim; i++)
1413        {   Dsymbol *member = (*members)[i];
1414
1415            if (member->hasStaticCtorOrDtor())
1416                return true;
1417        }
1418    }
1419    return false;
1420}
1421
1422/***************************************
1423 * Determine number of Dsymbols, folding in AttribDeclaration members.
1424 */
1425
1426static int dimDg(void *ctx, size_t, Dsymbol *)
1427{
1428    ++*(size_t *)ctx;
1429    return 0;
1430}
1431
1432size_t ScopeDsymbol::dim(Dsymbols *members)
1433{
1434    size_t n = 0;
1435    ScopeDsymbol_foreach(NULL, members, &dimDg, &n);
1436    return n;
1437}
1438
1439/***************************************
1440 * Get nth Dsymbol, folding in AttribDeclaration members.
1441 * Returns:
1442 *      Dsymbol*        nth Dsymbol
1443 *      NULL            not found, *pn gets incremented by the number
1444 *                      of Dsymbols
1445 */
1446
1447struct GetNthSymbolCtx
1448{
1449    size_t nth;
1450    Dsymbol *sym;
1451};
1452
1453static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym)
1454{
1455    GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx;
1456    if (n == p->nth)
1457    {   p->sym = sym;
1458        return 1;
1459    }
1460    return 0;
1461}
1462
1463Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *)
1464{
1465    GetNthSymbolCtx ctx = { nth, NULL };
1466    int res = ScopeDsymbol_foreach(NULL, members, &getNthSymbolDg, &ctx);
1467    return res ? ctx.sym : NULL;
1468}
1469
1470/***************************************
1471 * Expands attribute declarations in members in depth first
1472 * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each
1473 * member.
1474 * If dg returns !=0, stops and returns that value else returns 0.
1475 * Use this function to avoid the O(N + N^2/2) complexity of
1476 * calculating dim and calling N times getNth.
1477 */
1478
1479int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn)
1480{
1481    assert(dg);
1482    if (!members)
1483        return 0;
1484
1485    size_t n = pn ? *pn : 0; // take over index
1486    int result = 0;
1487    for (size_t i = 0; i < members->dim; i++)
1488    {   Dsymbol *s = (*members)[i];
1489
1490        if (AttribDeclaration *a = s->isAttribDeclaration())
1491            result = ScopeDsymbol_foreach(sc, a->include(sc, NULL), dg, ctx, &n);
1492        else if (TemplateMixin *tm = s->isTemplateMixin())
1493            result = ScopeDsymbol_foreach(sc, tm->members, dg, ctx, &n);
1494        else if (s->isTemplateInstance())
1495            ;
1496        else if (s->isUnitTestDeclaration())
1497            ;
1498        else
1499            result = dg(ctx, n++, s);
1500
1501        if (result)
1502            break;
1503    }
1504
1505    if (pn)
1506        *pn = n; // update index
1507    return result;
1508}
1509
1510/*******************************************
1511 * Look for member of the form:
1512 *      const(MemberInfo)[] getMembers(string);
1513 * Returns NULL if not found
1514 */
1515
1516FuncDeclaration *ScopeDsymbol::findGetMembers()
1517{
1518    Dsymbol *s = search_function(this, Id::getmembers);
1519    FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
1520
1521    if (fdx && fdx->isVirtual())
1522        fdx = NULL;
1523
1524    return fdx;
1525}
1526
1527
1528/****************************** WithScopeSymbol ******************************/
1529
1530WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
1531    : ScopeDsymbol()
1532{
1533    this->withstate = withstate;
1534}
1535
1536Dsymbol *WithScopeSymbol::search(const Loc &loc, Identifier *ident, int flags)
1537{
1538    //printf("WithScopeSymbol::search(%s)\n", ident->toChars());
1539    if (flags & SearchImportsOnly)
1540        return NULL;
1541
1542    // Acts as proxy to the with class declaration
1543    Dsymbol *s = NULL;
1544    Expression *eold = NULL;
1545    for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(_scope, e))
1546    {
1547        if (e->op == TOKscope)
1548        {
1549            s = ((ScopeExp *)e)->sds;
1550        }
1551        else if (e->op == TOKtype)
1552        {
1553            s = e->type->toDsymbol(NULL);
1554        }
1555        else
1556        {
1557            Type *t = e->type->toBasetype();
1558            s = t->toDsymbol(NULL);
1559        }
1560        if (s)
1561        {
1562            s = s->search(loc, ident, flags);
1563            if (s)
1564                return s;
1565        }
1566        eold = e;
1567    }
1568    return NULL;
1569}
1570
1571/****************************** ArrayScopeSymbol ******************************/
1572
1573ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e)
1574    : ScopeDsymbol()
1575{
1576    assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray);
1577    exp = e;
1578    type = NULL;
1579    td = NULL;
1580    this->sc = sc;
1581}
1582
1583ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t)
1584    : ScopeDsymbol()
1585{
1586    exp = NULL;
1587    type = t;
1588    td = NULL;
1589    this->sc = sc;
1590}
1591
1592ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
1593    : ScopeDsymbol()
1594{
1595    exp = NULL;
1596    type = NULL;
1597    td = s;
1598    this->sc = sc;
1599}
1600
1601Dsymbol *ArrayScopeSymbol::search(const Loc &loc, Identifier *ident, int)
1602{
1603    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
1604    if (ident == Id::dollar)
1605    {
1606        VarDeclaration **pvar;
1607        Expression *ce;
1608
1609    L1:
1610        if (td)
1611        {
1612            /* $ gives the number of elements in the tuple
1613             */
1614            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
1615            Expression *e = new IntegerExp(Loc(), td->objects->dim, Type::tsize_t);
1616            v->_init = new ExpInitializer(Loc(), e);
1617            v->storage_class |= STCtemp | STCstatic | STCconst;
1618            v->semantic(sc);
1619            return v;
1620        }
1621
1622        if (type)
1623        {
1624            /* $ gives the number of type entries in the type tuple
1625             */
1626            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
1627            Expression *e = new IntegerExp(Loc(), type->arguments->dim, Type::tsize_t);
1628            v->_init = new ExpInitializer(Loc(), e);
1629            v->storage_class |= STCtemp | STCstatic | STCconst;
1630            v->semantic(sc);
1631            return v;
1632        }
1633
1634        if (exp->op == TOKindex)
1635        {
1636            /* array[index] where index is some function of $
1637             */
1638            IndexExp *ie = (IndexExp *)exp;
1639            pvar = &ie->lengthVar;
1640            ce = ie->e1;
1641        }
1642        else if (exp->op == TOKslice)
1643        {
1644            /* array[lwr .. upr] where lwr or upr is some function of $
1645             */
1646            SliceExp *se = (SliceExp *)exp;
1647            pvar = &se->lengthVar;
1648            ce = se->e1;
1649        }
1650        else if (exp->op == TOKarray)
1651        {
1652            /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1653             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1654             */
1655            ArrayExp *ae = (ArrayExp *)exp;
1656            pvar = &ae->lengthVar;
1657            ce = ae->e1;
1658        }
1659        else
1660        {
1661            /* Didn't find $, look in enclosing scope(s).
1662             */
1663            return NULL;
1664        }
1665
1666        while (ce->op == TOKcomma)
1667            ce = ((CommaExp *)ce)->e2;
1668
1669        /* If we are indexing into an array that is really a type
1670         * tuple, rewrite this as an index into a type tuple and
1671         * try again.
1672         */
1673        if (ce->op == TOKtype)
1674        {
1675            Type *t = ((TypeExp *)ce)->type;
1676            if (t->ty == Ttuple)
1677            {
1678                type = (TypeTuple *)t;
1679                goto L1;
1680            }
1681        }
1682
1683        /* *pvar is lazily initialized, so if we refer to $
1684         * multiple times, it gets set only once.
1685         */
1686        if (!*pvar)             // if not already initialized
1687        {
1688            /* Create variable v and set it to the value of $
1689             */
1690            VarDeclaration *v;
1691            Type *t;
1692            if (ce->op == TOKtuple)
1693            {
1694                /* It is for an expression tuple, so the
1695                 * length will be a const.
1696                 */
1697                Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->dim, Type::tsize_t);
1698                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e));
1699                v->storage_class |= STCtemp | STCstatic | STCconst;
1700            }
1701            else if (ce->type && (t = ce->type->toBasetype()) != NULL &&
1702                     (t->ty == Tstruct || t->ty == Tclass))
1703            {
1704                // Look for opDollar
1705                assert(exp->op == TOKarray || exp->op == TOKslice);
1706                AggregateDeclaration *ad = isAggregate(t);
1707                assert(ad);
1708
1709                Dsymbol *s = ad->search(loc, Id::opDollar);
1710                if (!s)  // no dollar exists -- search in higher scope
1711                    return NULL;
1712                s = s->toAlias();
1713
1714                Expression *e = NULL;
1715                // Check for multi-dimensional opDollar(dim) template.
1716                if (TemplateDeclaration *td = s->isTemplateDeclaration())
1717                {
1718                    dinteger_t dim = 0;
1719                    if (exp->op == TOKarray)
1720                    {
1721                        dim = ((ArrayExp *)exp)->currentDimension;
1722                    }
1723                    else if (exp->op == TOKslice)
1724                    {
1725                        dim = 0; // slices are currently always one-dimensional
1726                    }
1727                    else
1728                    {
1729                        assert(0);
1730                    }
1731
1732                    Objects *tiargs = new Objects();
1733                    Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
1734                    edim = ::semantic(edim, sc);
1735                    tiargs->push(edim);
1736                    e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs);
1737                }
1738                else
1739                {
1740                    /* opDollar exists, but it's not a template.
1741                     * This is acceptable ONLY for single-dimension indexing.
1742                     * Note that it's impossible to have both template & function opDollar,
1743                     * because both take no arguments.
1744                     */
1745                    if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1)
1746                    {
1747                        exp->error("%s only defines opDollar for one dimension", ad->toChars());
1748                        return NULL;
1749                    }
1750                    Declaration *d = s->isDeclaration();
1751                    assert(d);
1752                    e = new DotVarExp(loc, ce, d);
1753                }
1754                e = ::semantic(e, sc);
1755                if (!e->type)
1756                    exp->error("%s has no value", e->toChars());
1757                t = e->type->toBasetype();
1758                if (t && t->ty == Tfunction)
1759                    e = new CallExp(e->loc, e);
1760                v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e));
1761                v->storage_class |= STCtemp | STCctfe | STCrvalue;
1762            }
1763            else
1764            {
1765                /* For arrays, $ will either be a compile-time constant
1766                 * (in which case its value in set during constant-folding),
1767                 * or a variable (in which case an expression is created in
1768                 * toir.c).
1769                 */
1770                VoidInitializer *e = new VoidInitializer(Loc());
1771                e->type = Type::tsize_t;
1772                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
1773                v->storage_class |= STCtemp | STCctfe; // it's never a true static variable
1774            }
1775            *pvar = v;
1776        }
1777        (*pvar)->semantic(sc);
1778        return (*pvar);
1779    }
1780    return NULL;
1781}
1782
1783
1784/****************************** DsymbolTable ******************************/
1785
1786DsymbolTable::DsymbolTable()
1787{
1788    tab = NULL;
1789}
1790
1791Dsymbol *DsymbolTable::lookup(Identifier const * const ident)
1792{
1793    //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
1794    return (Dsymbol *)dmd_aaGetRvalue(tab, const_cast<void *>((const void *)ident));
1795}
1796
1797Dsymbol *DsymbolTable::insert(Dsymbol *s)
1798{
1799    //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
1800    Identifier *ident = s->ident;
1801    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
1802    if (*ps)
1803        return NULL;            // already in table
1804    *ps = s;
1805    return s;
1806}
1807
1808Dsymbol *DsymbolTable::insert(Identifier const * const ident, Dsymbol *s)
1809{
1810    //printf("DsymbolTable::insert()\n");
1811    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, const_cast<void *>((const void *)ident));
1812    if (*ps)
1813        return NULL;            // already in table
1814    *ps = s;
1815    return s;
1816}
1817
1818Dsymbol *DsymbolTable::update(Dsymbol *s)
1819{
1820    Identifier *ident = s->ident;
1821    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
1822    *ps = s;
1823    return s;
1824}
1825
1826/****************************** Prot ******************************/
1827
1828Prot::Prot()
1829{
1830    this->kind = PROTundefined;
1831    this->pkg = NULL;
1832}
1833
1834Prot::Prot(PROTKIND kind)
1835{
1836    this->kind = kind;
1837    this->pkg = NULL;
1838}
1839
1840/**
1841 * Checks if `this` is superset of `other` restrictions.
1842 * For example, "protected" is more restrictive than "public".
1843 */
1844bool Prot::isMoreRestrictiveThan(const Prot other) const
1845{
1846    return this->kind < other.kind;
1847}
1848
1849/**
1850 * Checks if `this` is absolutely identical protection attribute to `other`
1851 */
1852bool Prot::operator==(const Prot& other) const
1853{
1854    if (this->kind == other.kind)
1855    {
1856        if (this->kind == PROTpackage)
1857            return this->pkg == other.pkg;
1858        return true;
1859    }
1860    return false;
1861}
1862
1863/**
1864 * Checks if parent defines different access restrictions than this one.
1865 *
1866 * Params:
1867 *  parent = protection attribute for scope that hosts this one
1868 *
1869 * Returns:
1870 *  'true' if parent is already more restrictive than this one and thus
1871 *  no differentiation is needed.
1872 */
1873bool Prot::isSubsetOf(const Prot& parent) const
1874{
1875    if (this->kind != parent.kind)
1876        return false;
1877
1878    if (this->kind == PROTpackage)
1879    {
1880        if (!this->pkg)
1881            return true;
1882        if (!parent.pkg)
1883            return false;
1884        if (parent.pkg->isAncestorPackageOf(this->pkg))
1885            return true;
1886    }
1887
1888    return true;
1889}
1890