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