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