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 
35 bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
36 typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
37 int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
38 Expression *semantic(Expression *e, Scope *sc);
39 
40 
41 /****************************** Dsymbol ******************************/
42 
Dsymbol()43 Dsymbol::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 
Dsymbol(Identifier * ident)61 Dsymbol::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 
create(Identifier * ident)79 Dsymbol *Dsymbol::create(Identifier *ident)
80 {
81     return new Dsymbol(ident);
82 }
83 
equals(RootObject * o)84 bool 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 
syntaxCopy(Dsymbol *)101 Dsymbol *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 
oneMember(Dsymbol ** ps,Identifier *)117 bool 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 
oneMembers(Dsymbols * members,Dsymbol ** ps,Identifier * ident)128 bool 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 
hasPointers()190 bool Dsymbol::hasPointers()
191 {
192     //printf("Dsymbol::hasPointers() %s\n", toChars());
193     return false;
194 }
195 
hasStaticCtorOrDtor()196 bool Dsymbol::hasStaticCtorOrDtor()
197 {
198     //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
199     return false;
200 }
201 
setFieldOffset(AggregateDeclaration *,unsigned *,bool)202 void Dsymbol::setFieldOffset(AggregateDeclaration *, unsigned *, bool)
203 {
204 }
205 
getIdent()206 Identifier *Dsymbol::getIdent()
207 {
208     return ident;
209 }
210 
toChars()211 const char *Dsymbol::toChars()
212 {
213     return ident ? ident->toChars() : "__anonymous";
214 }
215 
toPrettyCharsHelper()216 const char *Dsymbol::toPrettyCharsHelper()
217 {
218     return toChars();
219 }
220 
toPrettyChars(bool QualifyTypes)221 const 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 
getLoc()274 Loc& 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 
locToChars()286 const char *Dsymbol::locToChars()
287 {
288     return getLoc().toChars();
289 }
290 
kind()291 const 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  */
toAlias()301 Dsymbol *Dsymbol::toAlias()
302 {
303     return this;
304 }
305 
306 /*********************************
307  * Resolve recursive tuple expansion in eponymous template.
308  */
toAlias2()309 Dsymbol *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  */
pastMixin()322 Dsymbol *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
pastMixinAndNspace()333 Dsymbol *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  */
toParent()378 Dsymbol *Dsymbol::toParent()
379 {
380     return parent ? parent->pastMixinAndNspace() : NULL;
381 }
382 
383 /// ditto
toParent2()384 Dsymbol *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
toParent3()395 Dsymbol *Dsymbol::toParent3()
396 {
397     return parent ? parent->pastMixin() : NULL;
398 }
399 
isInstantiated()400 TemplateInstance *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.
isSpeculative()415 TemplateInstance *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 
ungagSpeculative()428 Ungag 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 
isAnonymous()438 bool 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 
setScope(Scope * sc)448 void 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 
importAll(Scope *)461 void Dsymbol::importAll(Scope *)
462 {
463 }
464 
465 /*************************************
466  * Does semantic analysis on the public face of declarations.
467  */
468 
semantic(Scope *)469 void 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 
semantic2(Scope *)478 void 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 
semantic3(Scope *)487 void 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 
search(const Loc &,Identifier *,int)502 Dsymbol *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 
symbol_search_fp(void * arg,const char * seed,int * cost)512 void *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 
search_correct(Identifier * ident)530 Dsymbol *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  */
searchX(Loc loc,Scope * sc,RootObject * id)544 Dsymbol *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 
overloadInsert(Dsymbol *)605 bool Dsymbol::overloadInsert(Dsymbol *)
606 {
607     //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
608     return false;
609 }
610 
size(Loc)611 d_uns64 Dsymbol::size(Loc)
612 {
613     error("Dsymbol '%s' has no size", toChars());
614     return SIZE_INVALID;
615 }
616 
isforwardRef()617 bool Dsymbol::isforwardRef()
618 {
619     return false;
620 }
621 
isThis()622 AggregateDeclaration *Dsymbol::isThis()
623 {
624     return NULL;
625 }
626 
isExport()627 bool Dsymbol::isExport() const
628 {
629     return false;
630 }
631 
isImportedSymbol()632 bool Dsymbol::isImportedSymbol() const
633 {
634     return false;
635 }
636 
isDeprecated()637 bool Dsymbol::isDeprecated()
638 {
639     return false;
640 }
641 
isOverloadable()642 bool Dsymbol::isOverloadable()
643 {
644     return false;
645 }
646 
isLabel()647 LabelDsymbol *Dsymbol::isLabel()                // is this a LabelDsymbol()?
648 {
649     return NULL;
650 }
651 
652 /// Returns an AggregateDeclaration when toParent() is that.
isMember()653 AggregateDeclaration *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.
isMember2()662 AggregateDeclaration *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?
isClassMember()671 ClassDeclaration *Dsymbol::isClassMember()
672 {
673     AggregateDeclaration *ad = isMember();
674     return ad ? ad->isClassDeclaration() : NULL;
675 }
676 
getType()677 Type *Dsymbol::getType()
678 {
679     return NULL;
680 }
681 
needThis()682 bool 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  */
apply(Dsymbol_apply_ft_t fp,void * param)698 int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
699 {
700     return (*fp)(this, param);
701 }
702 
addMember(Scope *,ScopeDsymbol * sds)703 void 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 
error(const char * format,...)731 void 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 
error(Loc loc,const char * format,...)739 void 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 
deprecation(Loc loc,const char * format,...)747 void 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 
deprecation(const char * format,...)755 void 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 
checkDeprecated(Loc loc,Scope * sc)763 void 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 
getModule()816 Module *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 
getAccessModule()838 Module *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 
prot()868 Prot Dsymbol::prot()
869 {
870     return Prot(PROTpublic);
871 }
872 
873 /*************************************
874  * Do syntax copy of an array of Dsymbol's.
875  */
876 
arraySyntaxCopy(Dsymbols * a)877 Dsymbols *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 
addComment(const utf8_t * comment)897 void 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  */
inNonRoot()913 bool 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 
OverloadSet(Identifier * ident,OverloadSet * os)934 OverloadSet::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 
push(Dsymbol * s)946 void OverloadSet::push(Dsymbol *s)
947 {
948     a.push(s);
949 }
950 
kind()951 const char *OverloadSet::kind() const
952 {
953     return "overloadset";
954 }
955 
956 
957 /********************************* ForwardingScopeDsymbol ******************/
958 
ForwardingScopeDsymbol(ScopeDsymbol * forward)959 ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol *forward)
960     : ScopeDsymbol()
961 {
962     this->forward = forward;
963 }
964 
symtabInsert(Dsymbol * s)965 Dsymbol *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  */
symtabLookup(Dsymbol * s,Identifier * id)996 Dsymbol *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 
importScope(Dsymbol * s,Prot protection)1020 void ForwardingScopeDsymbol::importScope(Dsymbol *s, Prot protection)
1021 {
1022     forward->importScope(s, protection);
1023 }
1024 
semantic(Scope *)1025 void ForwardingScopeDsymbol::semantic(Scope *)
1026 {
1027 }
1028 
kind()1029 const char *ForwardingScopeDsymbol::kind() const
1030 {
1031     return "local scope";
1032 }
1033 
1034 /********************************* ScopeDsymbol ****************************/
1035 
ScopeDsymbol()1036 ScopeDsymbol::ScopeDsymbol()
1037     : Dsymbol()
1038 {
1039     members = NULL;
1040     symtab = NULL;
1041     endlinnum = 0;
1042     importedScopes = NULL;
1043     prots = NULL;
1044 }
1045 
ScopeDsymbol(Identifier * id)1046 ScopeDsymbol::ScopeDsymbol(Identifier *id)
1047     : Dsymbol(id)
1048 {
1049     members = NULL;
1050     symtab = NULL;
1051     endlinnum = 0;
1052     importedScopes = NULL;
1053     prots = NULL;
1054 }
1055 
syntaxCopy(Dsymbol * s)1056 Dsymbol *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 
semantic(Scope *)1065 void 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 
search(const Loc & loc,Identifier * ident,int flags)1074 Dsymbol *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 
mergeOverloadSet(Identifier * ident,OverloadSet * os,Dsymbol * s)1224 OverloadSet *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 
importScope(Dsymbol * s,Prot protection)1274 void 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 
bitArraySet(BitArray * array,size_t idx)1304 static void bitArraySet(BitArray *array, size_t idx)
1305 {
1306     array->ptr[idx / BITS_PER_INDEX] |= 1ULL << (idx % BITS_PER_INDEX);
1307 }
1308 
bitArrayGet(BitArray * array,size_t idx)1309 static 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 
bitArrayLength(BitArray * array,size_t len)1315 static 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 
addAccessiblePackage(Package * p,Prot protection)1334 void 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 
isPackageAccessible(Package * p,Prot protection,int)1342 bool 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 
isforwardRef()1361 bool ScopeDsymbol::isforwardRef()
1362 {
1363     return (members == NULL);
1364 }
1365 
multiplyDefined(Loc loc,Dsymbol * s1,Dsymbol * s2)1366 void 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 
kind()1384 const char *ScopeDsymbol::kind() const
1385 {
1386     return "ScopeDsymbol";
1387 }
1388 
symtabInsert(Dsymbol * s)1389 Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s)
1390 {
1391     return symtab->insert(s);
1392 }
1393 
1394 /****************************************
1395  * Look up identifier in symbol table.
1396  */
1397 
symtabLookup(Dsymbol *,Identifier * id)1398 Dsymbol *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 
hasStaticCtorOrDtor()1408 bool 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 
dimDg(void * ctx,size_t,Dsymbol *)1426 static int dimDg(void *ctx, size_t, Dsymbol *)
1427 {
1428     ++*(size_t *)ctx;
1429     return 0;
1430 }
1431 
dim(Dsymbols * members)1432 size_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 
1447 struct GetNthSymbolCtx
1448 {
1449     size_t nth;
1450     Dsymbol *sym;
1451 };
1452 
getNthSymbolDg(void * ctx,size_t n,Dsymbol * sym)1453 static 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 
getNth(Dsymbols * members,size_t nth,size_t *)1463 Dsymbol *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 
ScopeDsymbol_foreach(Scope * sc,Dsymbols * members,ForeachDg dg,void * ctx,size_t * pn)1479 int 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 
findGetMembers()1516 FuncDeclaration *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 
WithScopeSymbol(WithStatement * withstate)1530 WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
1531     : ScopeDsymbol()
1532 {
1533     this->withstate = withstate;
1534 }
1535 
search(const Loc & loc,Identifier * ident,int flags)1536 Dsymbol *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 
ArrayScopeSymbol(Scope * sc,Expression * e)1573 ArrayScopeSymbol::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 
ArrayScopeSymbol(Scope * sc,TypeTuple * t)1583 ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t)
1584     : ScopeDsymbol()
1585 {
1586     exp = NULL;
1587     type = t;
1588     td = NULL;
1589     this->sc = sc;
1590 }
1591 
ArrayScopeSymbol(Scope * sc,TupleDeclaration * s)1592 ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
1593     : ScopeDsymbol()
1594 {
1595     exp = NULL;
1596     type = NULL;
1597     td = s;
1598     this->sc = sc;
1599 }
1600 
search(const Loc & loc,Identifier * ident,int)1601 Dsymbol *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 
DsymbolTable()1786 DsymbolTable::DsymbolTable()
1787 {
1788     tab = NULL;
1789 }
1790 
lookup(Identifier const * const ident)1791 Dsymbol *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 
insert(Dsymbol * s)1797 Dsymbol *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 
insert(Identifier const * const ident,Dsymbol * s)1808 Dsymbol *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 
update(Dsymbol * s)1818 Dsymbol *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 
Prot()1828 Prot::Prot()
1829 {
1830     this->kind = PROTundefined;
1831     this->pkg = NULL;
1832 }
1833 
Prot(PROTKIND kind)1834 Prot::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  */
isMoreRestrictiveThan(const Prot other)1844 bool 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  */
1852 bool 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  */
isSubsetOf(const Prot & parent)1873 bool 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