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