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