2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2020 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
11 #include "root/dsystem.h"
12 #include "root/rmem.h"
13 #include "root/speller.h"
18 #include "aggregate.h"
19 #include "identifier.h"
22 #include "expression.h"
23 #include "statement.h"
24 #include "declaration.h"
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
);
41 /****************************** Dsymbol ******************************/
45 //printf("Dsymbol::Dsymbol(%p)\n", this);
53 this->prettystring
= NULL
;
54 this->semanticRun
= PASSinit
;
57 this->userAttribDecl
= NULL
;
58 this->ddocUnittest
= NULL
;
61 Dsymbol::Dsymbol(Identifier
*ident
)
63 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
71 this->prettystring
= NULL
;
72 this->semanticRun
= PASSinit
;
75 this->userAttribDecl
= NULL
;
76 this->ddocUnittest
= NULL
;
79 Dsymbol
*Dsymbol::create(Identifier
*ident
)
81 return new Dsymbol(ident
);
84 bool Dsymbol::equals(RootObject
*o
)
88 Dsymbol
*s
= (Dsymbol
*)(o
);
89 // Overload sets don't have an ident
90 if (s
&& ident
&& s
->ident
&& ident
->equals(s
->ident
))
95 /**************************************
97 * Used for template instantiations.
98 * If s is NULL, allocate the new object, otherwise fill it in.
101 Dsymbol
*Dsymbol::syntaxCopy(Dsymbol
*)
104 printf("%s %s\n", kind(), toChars());
109 /**************************************
110 * Determine if this symbol is only one.
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
117 bool Dsymbol::oneMember(Dsymbol
**ps
, Identifier
*)
119 //printf("Dsymbol::oneMember()\n");
124 /*****************************************
125 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
128 bool Dsymbol::oneMembers(Dsymbols
*members
, Dsymbol
**ps
, Identifier
*ident
)
130 //printf("Dsymbol::oneMembers() %d\n", members ? members->length : 0);
135 for (size_t i
= 0; i
< members
->length
; i
++)
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);
142 //printf("\tfalse 1\n");
149 if (!(*ps
)->ident
|| !(*ps
)->ident
->equals(ident
))
153 else if (s
->isOverloadable() && (*ps
)->isOverloadable())
155 // keep head of overload set
156 FuncDeclaration
*f1
= s
->isFuncDeclaration();
157 FuncDeclaration
*f2
= (*ps
)->isFuncDeclaration();
160 assert(!f1
->isFuncAliasDeclaration());
161 assert(!f2
->isFuncAliasDeclaration());
162 for (; f1
!= f2
; f1
= f1
->overnext0
)
164 if (f1
->overnext0
== NULL
)
172 else // more than one symbol
175 //printf("\tfalse 2\n");
181 *ps
= s
; // s is the one symbol, NULL if none
182 //printf("\ttrue\n");
186 /*****************************************
187 * Is Dsymbol a variable that contains pointers?
190 bool Dsymbol::hasPointers()
192 //printf("Dsymbol::hasPointers() %s\n", toChars());
196 bool Dsymbol::hasStaticCtorOrDtor()
198 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
202 void Dsymbol::setFieldOffset(AggregateDeclaration
*, unsigned *, bool)
206 Identifier
*Dsymbol::getIdent()
211 const char *Dsymbol::toChars()
213 return ident
? ident
->toChars() : "__anonymous";
216 const char *Dsymbol::toPrettyCharsHelper()
221 const char *Dsymbol::toPrettyChars(bool QualifyTypes
)
223 if (prettystring
&& !QualifyTypes
)
224 return (const char *)prettystring
;
226 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
229 const char *s
= toChars();
231 prettystring
= (const utf8_t
*)s
;
235 // Computer number of components
236 size_t complength
= 0;
237 for (Dsymbol
*p
= this; p
; p
= p
->parent
)
240 // Allocate temporary array comp[]
241 const char **comp
= (const char **)mem
.xmalloc(complength
* sizeof(char**));
243 // Fill in comp[] and compute length of final result
246 for (Dsymbol
*p
= this; p
; p
= p
->parent
)
248 const char *s
= QualifyTypes
? p
->toPrettyCharsHelper() : p
->toChars();
249 const size_t len
= strlen(s
);
255 char *s
= (char *)mem
.xmalloc(length
);
256 char *q
= s
+ length
- 1;
258 for (size_t j
= 0; j
< complength
; j
++)
260 const char *t
= comp
[j
];
261 const size_t len
= strlen(t
);
270 prettystring
= (utf8_t
*)s
;
274 Loc
& Dsymbol::getLoc()
276 if (!loc
.filename
) // avoid bug 5861.
278 Module
*m
= getModule();
281 loc
.filename
= m
->srcfile
->toChars();
286 const char *Dsymbol::locToChars()
288 return getLoc().toChars();
291 const char *Dsymbol::kind() const
296 /*********************************
297 * If this symbol is really an alias for another,
299 * If needed, semantic() is invoked due to resolve forward reference.
301 Dsymbol
*Dsymbol::toAlias()
306 /*********************************
307 * Resolve recursive tuple expansion in eponymous template.
309 Dsymbol
*Dsymbol::toAlias2()
315 * `pastMixin` returns the enclosing symbol if this is a template mixin.
317 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
320 * See also `parent`, `toParent`, `toParent2` and `toParent3`.
322 Dsymbol
*Dsymbol::pastMixin()
324 //printf("Dsymbol::pastMixin() %s\n", toChars());
325 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
329 return parent
->pastMixin();
333 Dsymbol
*Dsymbol::pastMixinAndNspace()
335 //printf("Dsymbol::pastMixinAndNspace() %s\n", toChars());
336 Nspace
*ns
= isNspace();
337 if (!(ns
&& ns
->mangleOnly
) &&
338 !isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
342 return parent
->pastMixinAndNspace();
345 /**********************************
346 * `parent` field returns a lexically enclosing scope symbol this is a member of.
348 * `toParent()` returns a logically enclosing scope symbol this is a member of.
349 * It skips over TemplateMixin's and Nspaces that are mangleOnly.
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.
355 * `toParent3()` returns a logically enclosing scope symbol this is a member of.
356 * It skips over TemplateMixin's.
360 * template Foo(alias a) { mixin Bar!(); }
361 * mixin template Bar() {
362 * public { // ProtDeclaration
363 * void baz() { a = 2; }
368 * alias foo = Foo!(v);
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')
378 Dsymbol
*Dsymbol::toParent()
380 return parent
? parent
->pastMixinAndNspace() : NULL
;
384 Dsymbol
*Dsymbol::toParent2()
387 (!parent
->isTemplateInstance() &&
388 !parent
->isForwardingAttribDeclaration() &&
389 !parent
->isForwardingScopeDsymbol()))
391 return parent
->toParent2();
395 Dsymbol
*Dsymbol::toParent3()
397 return parent
? parent
->pastMixin() : NULL
;
400 TemplateInstance
*Dsymbol::isInstantiated()
402 for (Dsymbol
*s
= parent
; s
; s
= s
->parent
)
404 TemplateInstance
*ti
= s
->isTemplateInstance();
405 if (ti
&& !ti
->isTemplateMixin())
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.
415 TemplateInstance
*Dsymbol::isSpeculative()
417 Dsymbol
*par
= parent
;
420 TemplateInstance
*ti
= par
->isTemplateInstance();
421 if (ti
&& ti
->gagged
)
423 par
= par
->toParent();
428 Ungag
Dsymbol::ungagSpeculative()
430 unsigned oldgag
= global
.gag
;
432 if (global
.gag
&& !isSpeculative() && !toParent2()->isFuncDeclaration())
435 return Ungag(oldgag
);
438 bool Dsymbol::isAnonymous()
440 return ident
== NULL
;
443 /*************************************
444 * Set scope for future semantic analysis so we can
445 * deal better with forward references.
448 void Dsymbol::setScope(Scope
*sc
)
450 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
452 sc
->setNoFree(); // may need it even after semantic() finishes
455 depdecl
= sc
->depdecl
;
458 userAttribDecl
= sc
->userAttribDecl
;
461 void Dsymbol::importAll(Scope
*)
465 /*************************************
466 * Does semantic analysis on the public face of declarations.
469 void Dsymbol::semantic(Scope
*)
471 error("%p has no semantic routine", this);
474 /*************************************
475 * Does semantic analysis on initializers and members of aggregates.
478 void Dsymbol::semantic2(Scope
*)
480 // Most Dsymbols have no further semantic analysis needed
483 /*************************************
484 * Does semantic analysis on function bodies.
487 void Dsymbol::semantic3(Scope
*)
489 // Most Dsymbols have no further semantic analysis needed
492 /*********************************************
493 * Search for ident as member of s.
495 * loc = location to print for error messages
496 * ident = identifier to search for
502 Dsymbol
*Dsymbol::search(const Loc
&, Identifier
*, int)
504 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
508 /***************************************************
509 * Search for symbol with correct spelling.
512 void *symbol_search_fp(void *arg
, const char *seed
, int *cost
)
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.
517 size_t len
= strlen(seed
);
520 Identifier
*id
= Identifier::lookup(seed
, len
);
525 Dsymbol
*s
= (Dsymbol
*)arg
;
526 Module::clearCache();
527 return (void *)s
->search(Loc(), id
, IgnoreErrors
);
530 Dsymbol
*Dsymbol::search_correct(Identifier
*ident
)
533 return NULL
; // don't do it for speculative compiles; too time consuming
535 return (Dsymbol
*)speller(ident
->toChars(), &symbol_search_fp
, (void *)this, idchars
);
538 /***************************************
539 * Search for identifier id as a member of 'this'.
540 * id may be a template instance.
542 * symbol found, NULL if not
544 Dsymbol
*Dsymbol::searchX(Loc loc
, Scope
*sc
, RootObject
*id
)
546 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
547 Dsymbol
*s
= toAlias();
550 if (Declaration
*d
= s
->isDeclaration())
554 ::error(loc
, "circular reference to '%s'", d
->toPrettyChars());
559 switch (id
->dyncast())
561 case DYNCAST_IDENTIFIER
:
562 sm
= s
->search(loc
, (Identifier
*)id
);
565 case DYNCAST_DSYMBOL
:
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
);
574 sm
= s
->search_correct(ti
->name
);
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());
579 ::error(loc
, "template identifier '%s' is not a member of %s '%s'",
580 ti
->name
->toChars(), s
->kind(), s
->toPrettyChars());
584 TemplateDeclaration
*td
= sm
->isTemplateDeclaration();
587 ::error(loc
, "%s.%s is not a template, it is a %s", s
->toPrettyChars(), ti
->name
->toChars(), sm
->kind());
591 if (!ti
->semanticRun
)
598 case DYNCAST_EXPRESSION
:
605 bool Dsymbol::overloadInsert(Dsymbol
*)
607 //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
611 d_uns64
Dsymbol::size(Loc
)
613 error("Dsymbol '%s' has no size", toChars());
617 bool Dsymbol::isforwardRef()
622 AggregateDeclaration
*Dsymbol::isThis()
627 bool Dsymbol::isExport() const
632 bool Dsymbol::isImportedSymbol() const
637 bool Dsymbol::isDeprecated()
642 bool Dsymbol::isOverloadable()
647 LabelDsymbol
*Dsymbol::isLabel() // is this a LabelDsymbol()?
652 /// Returns an AggregateDeclaration when toParent() is that.
653 AggregateDeclaration
*Dsymbol::isMember()
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
;
661 /// Returns an AggregateDeclaration when toParent2() is that.
662 AggregateDeclaration
*Dsymbol::isMember2()
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
;
670 // is this a member of a ClassDeclaration?
671 ClassDeclaration
*Dsymbol::isClassMember()
673 AggregateDeclaration
*ad
= isMember();
674 return ad
? ad
->isClassDeclaration() : NULL
;
677 Type
*Dsymbol::getType()
682 bool Dsymbol::needThis()
687 /*********************************
688 * Iterate this dsymbol or members of this scoped dsymbol, then
689 * call `fp` with the found symbol and `param`.
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.
695 * nonzero if the iteration is aborted by the return value of fp,
696 * or 0 if it's completed.
698 int Dsymbol::apply(Dsymbol_apply_ft_t fp
, void *param
)
700 return (*fp
)(this, param
);
703 void Dsymbol::addMember(Scope
*, ScopeDsymbol
*sds
)
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);
709 if (!isAnonymous()) // no name, so can't add it to symbol table
711 if (!sds
->symtabInsert(this)) // if name is already defined
713 Dsymbol
*s2
= sds
->symtabLookup(this, ident
);
714 if (!s2
->overloadInsert(this))
716 sds
->multiplyDefined(Loc(), this, s2
);
720 if (sds
->isAggregateDeclaration() || sds
->isEnumDeclaration())
722 if (ident
== Id::__sizeof
|| ident
== Id::__xalignof
|| ident
== Id::_mangleof
)
724 error(".%s property cannot be redefined", ident
->toChars());
731 void Dsymbol::error(const char *format
, ...)
734 va_start(ap
, format
);
735 ::verror(getLoc(), format
, ap
, kind(), toPrettyChars());
739 void Dsymbol::error(Loc loc
, const char *format
, ...)
742 va_start(ap
, format
);
743 ::verror(loc
, format
, ap
, kind(), toPrettyChars());
747 void Dsymbol::deprecation(Loc loc
, const char *format
, ...)
750 va_start(ap
, format
);
751 ::vdeprecation(loc
, format
, ap
, kind(), toPrettyChars());
755 void Dsymbol::deprecation(const char *format
, ...)
758 va_start(ap
, format
);
759 ::vdeprecation(getLoc(), format
, ap
, kind(), toPrettyChars());
763 void Dsymbol::checkDeprecated(Loc loc
, Scope
*sc
)
765 if (global
.params
.useDeprecated
!= DIAGNOSTICoff
&& isDeprecated())
767 // Don't complain if we're inside a deprecated symbol's scope
768 for (Dsymbol
*sp
= sc
->parent
; sp
; sp
= sp
->parent
)
770 if (sp
->isDeprecated())
774 for (Scope
*sc2
= sc
; sc2
; sc2
= sc2
->enclosing
)
776 if (sc2
->scopesym
&& sc2
->scopesym
->isDeprecated())
779 // If inside a StorageClassDeclaration that is deprecated
780 if (sc2
->stc
& STCdeprecated
)
784 const char *message
= NULL
;
785 for (Dsymbol
*p
= this; p
; p
= p
->parent
)
787 message
= p
->depdecl
? p
->depdecl
->getMessage() : NULL
;
793 deprecation(loc
, "is deprecated - %s", message
);
795 deprecation(loc
, "is deprecated");
799 Declaration
*d
= isDeclaration();
800 if (d
&& d
->storage_class
& STCdisable
)
802 if (!(sc
->func
&& sc
->func
->storage_class
& STCdisable
))
804 if (d
->toParent() && d
->isPostBlitDeclaration())
805 d
->toParent()->error(loc
, "is not copyable because it is annotated with @disable");
807 error(loc
, "is not callable because it is annotated with @disable");
812 /**********************************
813 * Determine which Module a Dsymbol is in.
816 Module
*Dsymbol::getModule()
818 //printf("Dsymbol::getModule()\n");
819 if (TemplateInstance
*ti
= isInstantiated())
820 return ti
->tempdecl
->getModule();
825 //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
826 Module
*m
= s
->isModule();
834 /**********************************
835 * Determine which Module a Dsymbol is in, as far as access rights go.
838 Module
*Dsymbol::getAccessModule()
840 //printf("Dsymbol::getAccessModule()\n");
841 if (TemplateInstance
*ti
= isInstantiated())
842 return ti
->tempdecl
->getAccessModule();
847 //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
848 Module
*m
= s
->isModule();
851 TemplateInstance
*ti
= s
->isTemplateInstance();
852 if (ti
&& ti
->enclosing
)
854 /* Because of local template instantiation, the parent isn't where the access
855 * rights come from - it's the template declaration
865 /*************************************
870 return Prot(PROTpublic
);
873 /*************************************
874 * Do syntax copy of an array of Dsymbol's.
877 Dsymbols
*Dsymbol::arraySyntaxCopy(Dsymbols
*a
)
884 for (size_t i
= 0; i
< b
->length
; i
++)
886 (*b
)[i
] = (*b
)[i
]->syntaxCopy(NULL
);
892 /****************************************
893 * Add documentation comment to Dsymbol.
894 * Ignore NULL comments.
897 void Dsymbol::addComment(const utf8_t
*comment
)
900 //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
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
);
910 /****************************************
911 * Returns true if this symbol is defined in a non-root module without instantiation.
913 bool Dsymbol::inNonRoot()
916 for (; s
; s
= s
->toParent())
918 if (s
->isTemplateInstance())
922 if (Module
*m
= s
->isModule())
932 /********************************* OverloadSet ****************************/
934 OverloadSet::OverloadSet(Identifier
*ident
, OverloadSet
*os
)
939 for (size_t i
= 0; i
< os
->a
.length
; i
++)
946 void OverloadSet::push(Dsymbol
*s
)
951 const char *OverloadSet::kind() const
953 return "overloadset";
957 /********************************* ForwardingScopeDsymbol ******************/
959 ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol
*forward
)
962 this->forward
= forward
;
965 Dsymbol
*ForwardingScopeDsymbol::symtabInsert(Dsymbol
*s
)
968 if (Declaration
*d
= s
->isDeclaration())
970 if (d
->storage_class
& STClocal
)
972 // Symbols with storage class STClocal are not
973 // forwarded, but stored in the local symbol
974 // table. (Those are the `static foreach` variables.)
977 symtab
= new DsymbolTable();
979 return ScopeDsymbol::symtabInsert(s
); // insert locally
982 if (!forward
->symtab
)
984 forward
->symtab
= new DsymbolTable();
986 // Non-STClocal symbols are forwarded to `forward`.
987 return forward
->symtabInsert(s
);
990 /************************
991 * This override handles the following two cases:
992 * static foreach (i, i; [0]) { ... }
994 * static foreach (i; [0]) { enum i = 2; }
996 Dsymbol
*ForwardingScopeDsymbol::symtabLookup(Dsymbol
*s
, Identifier
*id
)
999 // correctly diagnose clashing foreach loop variables.
1000 if (Declaration
*d
= s
->isDeclaration())
1002 if (d
->storage_class
& STClocal
)
1006 symtab
= new DsymbolTable();
1008 return ScopeDsymbol::symtabLookup(s
,id
);
1011 // Declarations within `static foreach` do not clash with
1012 // `static foreach` loop variables.
1013 if (!forward
->symtab
)
1015 forward
->symtab
= new DsymbolTable();
1017 return forward
->symtabLookup(s
,id
);
1020 void ForwardingScopeDsymbol::importScope(Dsymbol
*s
, Prot protection
)
1022 forward
->importScope(s
, protection
);
1025 void ForwardingScopeDsymbol::semantic(Scope
*)
1029 const char *ForwardingScopeDsymbol::kind() const
1031 return "local scope";
1034 /********************************* ScopeDsymbol ****************************/
1036 ScopeDsymbol::ScopeDsymbol()
1042 importedScopes
= NULL
;
1046 ScopeDsymbol::ScopeDsymbol(Identifier
*id
)
1052 importedScopes
= NULL
;
1056 Dsymbol
*ScopeDsymbol::syntaxCopy(Dsymbol
*s
)
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
;
1065 void ScopeDsymbol::semantic(Scope
*)
1069 /*****************************************
1070 * This function is #1 on the list of functions that eat cpu time.
1071 * Be very, very careful about slowing it down.
1074 Dsymbol
*ScopeDsymbol::search(const Loc
&loc
, Identifier
*ident
, int flags
)
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;
1079 // Look in symbols declared in this module
1080 if (symtab
&& !(flags
& SearchImportsOnly
))
1082 //printf(" look in locals\n");
1083 Dsymbol
*s1
= symtab
->lookup(ident
);
1086 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars());
1090 //printf(" not found in locals\n");
1092 // Look in imported scopes
1095 //printf(" look in imports\n");
1097 OverloadSet
*a
= NULL
;
1099 // Look in imported modules
1100 for (size_t i
= 0; i
< importedScopes
->length
; i
++)
1102 // If private import, don't search it
1103 if ((flags
& IgnorePrivateImports
) && prots
[i
] == PROTprivate
)
1106 int sflags
= flags
& (IgnoreErrors
| IgnoreAmbiguous
| IgnoreSymbolVisibility
); // remember these in recursive searches
1107 Dsymbol
*ss
= (*importedScopes
)[i
];
1109 //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
1113 if (flags
& SearchLocalsOnly
)
1116 else // mixin template
1118 if (flags
& SearchImportsOnly
)
1120 // compatibility with -transition=import (Bugzilla 15925)
1121 // SearchLocalsOnly should always get set for new lookup rules
1122 sflags
|= (flags
& SearchLocalsOnly
);
1125 /* Don't find private members if ss is a module
1127 Dsymbol
*s2
= ss
->search(loc
, ident
, sflags
| (ss
->isModule() ? IgnorePrivateImports
: IgnoreNone
));
1128 if (!s2
|| (!(flags
& IgnoreSymbolVisibility
) && !symbolIsVisible(this, s2
)))
1133 if (s
&& s
->isOverloadSet())
1134 a
= mergeOverloadSet(ident
, a
, s
);
1136 else if (s2
&& s
!= s2
)
1138 if (s
->toAlias() == s2
->toAlias() ||
1139 (s
->getType() == s2
->getType() && s
->getType()))
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
1146 if (s
->isDeprecated() ||
1147 (s
->prot().isMoreRestrictiveThan(s2
->prot()) && s2
->prot().kind
!= PROTnone
))
1152 /* Two imports of the same module should be regarded as
1155 Import
*i1
= s
->isImport();
1156 Import
*i2
= s2
->isImport();
1158 (i1
->mod
== i2
->mod
||
1159 (!i1
->parent
->isImport() && !i2
->parent
->isImport() &&
1160 i1
->ident
->equals(i2
->ident
))
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.
1173 /* If both s2 and s are overloadable (though we only
1174 * need to check s once)
1176 if ((s2
->isOverloadSet() || s2
->isOverloadable()) &&
1177 (a
|| s
->isOverloadable()))
1179 a
= mergeOverloadSet(ident
, a
, s2
);
1182 if (flags
& IgnoreAmbiguous
) // if return NULL on ambiguity
1184 if (!(flags
& IgnoreErrors
))
1185 ScopeDsymbol::multiplyDefined(loc
, s
, s2
);
1194 /* Build special symbol if we had multiple finds
1198 if (!s
->isOverloadSet())
1199 a
= mergeOverloadSet(ident
, a
, s
);
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())
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
))
1213 error(loc
, "%s %s is private", s
->kind(), s
->toPrettyChars());
1215 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1218 //printf(" not found in imports\n");
1224 OverloadSet
*ScopeDsymbol::mergeOverloadSet(Identifier
*ident
, OverloadSet
*os
, Dsymbol
*s
)
1228 os
= new OverloadSet(ident
);
1231 if (OverloadSet
*os2
= s
->isOverloadSet())
1233 // Merge the cross-module overload set 'os2' into 'os'
1234 if (os
->a
.length
== 0)
1236 os
->a
.setDim(os2
->a
.length
);
1237 memcpy(os
->a
.tdata(), os2
->a
.tdata(), sizeof(os
->a
[0]) * os2
->a
.length
);
1241 for (size_t i
= 0; i
< os2
->a
.length
; i
++)
1243 os
= mergeOverloadSet(ident
, os
, os2
->a
[i
]);
1249 assert(s
->isOverloadable());
1251 /* Don't add to os[] if s is alias of previous sym
1253 for (size_t j
= 0; j
< os
->a
.length
; j
++)
1255 Dsymbol
*s2
= os
->a
[j
];
1256 if (s
->toAlias() == s2
->toAlias())
1258 if (s2
->isDeprecated() ||
1259 (s2
->prot().isMoreRestrictiveThan(s
->prot()) &&
1260 s
->prot().kind
!= PROTnone
))
1274 void ScopeDsymbol::importScope(Dsymbol
*s
, Prot protection
)
1276 //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
1278 // No circular or redundant import's
1281 if (!importedScopes
)
1282 importedScopes
= new Dsymbols();
1285 for (size_t i
= 0; i
< importedScopes
->length
; i
++)
1287 Dsymbol
*ss
= (*importedScopes
)[i
];
1288 if (ss
== s
) // if already imported
1290 if (protection
.kind
> prots
[i
])
1291 prots
[i
] = protection
.kind
; // upgrade access
1296 importedScopes
->push(s
);
1297 prots
= (PROTKIND
*)mem
.xrealloc(prots
, importedScopes
->length
* sizeof(prots
[0]));
1298 prots
[importedScopes
->length
- 1] = protection
.kind
;
1302 #define BITS_PER_INDEX (sizeof(size_t) * CHAR_BIT)
1304 static void bitArraySet(BitArray
*array
, size_t idx
)
1306 array
->ptr
[idx
/ BITS_PER_INDEX
] |= 1ULL << (idx
% BITS_PER_INDEX
);
1309 static bool bitArrayGet(BitArray
*array
, size_t idx
)
1311 const size_t boffset
= idx
% BITS_PER_INDEX
;
1312 return (array
->ptr
[idx
/ BITS_PER_INDEX
] & (1ULL << boffset
)) >> boffset
;
1315 static void bitArrayLength(BitArray
*array
, size_t len
)
1317 if (array
->len
< len
)
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
;
1323 array
->ptr
= (size_t *)mem
.xmalloc(nbytes
* sizeof(size_t));
1325 array
->ptr
= (size_t *)mem
.xrealloc(array
->ptr
, nbytes
* sizeof(size_t));
1327 for (size_t i
= obytes
; i
< nbytes
; i
++)
1330 array
->len
= nbytes
* BITS_PER_INDEX
;
1334 void ScopeDsymbol::addAccessiblePackage(Package
*p
, Prot protection
)
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
);
1342 bool ScopeDsymbol::isPackageAccessible(Package
*p
, Prot protection
, int)
1344 if ((p
->tag
< accessiblePackages
.len
&& bitArrayGet(&accessiblePackages
, p
->tag
)) ||
1345 (protection
.kind
== PROTprivate
&& p
->tag
< privateAccessiblePackages
.len
&& bitArrayGet(&privateAccessiblePackages
, p
->tag
)))
1349 for (size_t i
= 0; i
< importedScopes
->length
; i
++)
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
))
1361 bool ScopeDsymbol::isforwardRef()
1363 return (members
== NULL
);
1366 void ScopeDsymbol::multiplyDefined(Loc loc
, Dsymbol
*s1
, Dsymbol
*s2
)
1369 { ::error(loc
, "%s at %s conflicts with %s at %s",
1370 s1
->toPrettyChars(),
1372 s2
->toPrettyChars(),
1377 s1
->error(s1
->loc
, "conflicts with %s %s at %s",
1379 s2
->toPrettyChars(),
1384 const char *ScopeDsymbol::kind() const
1386 return "ScopeDsymbol";
1389 Dsymbol
*ScopeDsymbol::symtabInsert(Dsymbol
*s
)
1391 return symtab
->insert(s
);
1394 /****************************************
1395 * Look up identifier in symbol table.
1398 Dsymbol
*ScopeDsymbol::symtabLookup(Dsymbol
*, Identifier
*id
)
1400 return symtab
->lookup(id
);
1403 /****************************************
1404 * Return true if any of the members are static ctors or static dtors, or if
1405 * any members have members that are.
1408 bool ScopeDsymbol::hasStaticCtorOrDtor()
1412 for (size_t i
= 0; i
< members
->length
; i
++)
1413 { Dsymbol
*member
= (*members
)[i
];
1415 if (member
->hasStaticCtorOrDtor())
1422 /***************************************
1423 * Determine number of Dsymbols, folding in AttribDeclaration members.
1426 static int dimDg(void *ctx
, size_t, Dsymbol
*)
1432 size_t ScopeDsymbol::dim(Dsymbols
*members
)
1435 ScopeDsymbol_foreach(NULL
, members
, &dimDg
, &n
);
1439 /***************************************
1440 * Get nth Dsymbol, folding in AttribDeclaration members.
1442 * Dsymbol* nth Dsymbol
1443 * NULL not found, *pn gets incremented by the number
1447 struct GetNthSymbolCtx
1453 static int getNthSymbolDg(void *ctx
, size_t n
, Dsymbol
*sym
)
1455 GetNthSymbolCtx
*p
= (GetNthSymbolCtx
*)ctx
;
1463 Dsymbol
*ScopeDsymbol::getNth(Dsymbols
*members
, size_t nth
, size_t *)
1465 GetNthSymbolCtx ctx
= { nth
, NULL
};
1466 int res
= ScopeDsymbol_foreach(NULL
, members
, &getNthSymbolDg
, &ctx
);
1467 return res
? ctx
.sym
: NULL
;
1470 /***************************************
1471 * Expands attribute declarations in members in depth first
1472 * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each
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.
1479 int ScopeDsymbol_foreach(Scope
*sc
, Dsymbols
*members
, ForeachDg dg
, void *ctx
, size_t *pn
)
1485 size_t n
= pn
? *pn
: 0; // take over index
1487 for (size_t i
= 0; i
< members
->length
; i
++)
1488 { Dsymbol
*s
= (*members
)[i
];
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())
1496 else if (s
->isUnitTestDeclaration())
1499 result
= dg(ctx
, n
++, s
);
1506 *pn
= n
; // update index
1510 /*******************************************
1511 * Look for member of the form:
1512 * const(MemberInfo)[] getMembers(string);
1513 * Returns NULL if not found
1516 FuncDeclaration
*ScopeDsymbol::findGetMembers()
1518 Dsymbol
*s
= search_function(this, Id::getmembers
);
1519 FuncDeclaration
*fdx
= s
? s
->isFuncDeclaration() : NULL
;
1521 if (fdx
&& fdx
->isVirtual())
1528 /****************************** WithScopeSymbol ******************************/
1530 WithScopeSymbol::WithScopeSymbol(WithStatement
*withstate
)
1533 this->withstate
= withstate
;
1536 Dsymbol
*WithScopeSymbol::search(const Loc
&loc
, Identifier
*ident
, int flags
)
1538 //printf("WithScopeSymbol::search(%s)\n", ident->toChars());
1539 if (flags
& SearchImportsOnly
)
1542 // Acts as proxy to the with class declaration
1544 Expression
*eold
= NULL
;
1545 for (Expression
*e
= withstate
->exp
; e
!= eold
; e
= resolveAliasThis(_scope
, e
))
1547 if (e
->op
== TOKscope
)
1549 s
= ((ScopeExp
*)e
)->sds
;
1551 else if (e
->op
== TOKtype
)
1553 s
= e
->type
->toDsymbol(NULL
);
1557 Type
*t
= e
->type
->toBasetype();
1558 s
= t
->toDsymbol(NULL
);
1562 s
= s
->search(loc
, ident
, flags
);
1571 /****************************** ArrayScopeSymbol ******************************/
1573 ArrayScopeSymbol::ArrayScopeSymbol(Scope
*sc
, Expression
*e
)
1576 assert(e
->op
== TOKindex
|| e
->op
== TOKslice
|| e
->op
== TOKarray
);
1583 ArrayScopeSymbol::ArrayScopeSymbol(Scope
*sc
, TypeTuple
*t
)
1592 ArrayScopeSymbol::ArrayScopeSymbol(Scope
*sc
, TupleDeclaration
*s
)
1601 Dsymbol
*ArrayScopeSymbol::search(const Loc
&loc
, Identifier
*ident
, int)
1603 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
1604 if (ident
== Id::dollar
)
1606 VarDeclaration
**pvar
;
1612 /* $ gives the number of elements in the tuple
1614 VarDeclaration
*v
= new VarDeclaration(loc
, Type::tsize_t
, Id::dollar
, NULL
);
1615 Expression
*e
= new IntegerExp(Loc(), td
->objects
->length
, Type::tsize_t
);
1616 v
->_init
= new ExpInitializer(Loc(), e
);
1617 v
->storage_class
|= STCtemp
| STCstatic
| STCconst
;
1624 /* $ gives the number of type entries in the type tuple
1626 VarDeclaration
*v
= new VarDeclaration(loc
, Type::tsize_t
, Id::dollar
, NULL
);
1627 Expression
*e
= new IntegerExp(Loc(), type
->arguments
->length
, Type::tsize_t
);
1628 v
->_init
= new ExpInitializer(Loc(), e
);
1629 v
->storage_class
|= STCtemp
| STCstatic
| STCconst
;
1634 if (exp
->op
== TOKindex
)
1636 /* array[index] where index is some function of $
1638 IndexExp
*ie
= (IndexExp
*)exp
;
1639 pvar
= &ie
->lengthVar
;
1642 else if (exp
->op
== TOKslice
)
1644 /* array[lwr .. upr] where lwr or upr is some function of $
1646 SliceExp
*se
= (SliceExp
*)exp
;
1647 pvar
= &se
->lengthVar
;
1650 else if (exp
->op
== TOKarray
)
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,...)
1655 ArrayExp
*ae
= (ArrayExp
*)exp
;
1656 pvar
= &ae
->lengthVar
;
1661 /* Didn't find $, look in enclosing scope(s).
1666 while (ce
->op
== TOKcomma
)
1667 ce
= ((CommaExp
*)ce
)->e2
;
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
1673 if (ce
->op
== TOKtype
)
1675 Type
*t
= ((TypeExp
*)ce
)->type
;
1676 if (t
->ty
== Ttuple
)
1678 type
= (TypeTuple
*)t
;
1683 /* *pvar is lazily initialized, so if we refer to $
1684 * multiple times, it gets set only once.
1686 if (!*pvar
) // if not already initialized
1688 /* Create variable v and set it to the value of $
1692 if (ce
->op
== TOKtuple
)
1694 /* It is for an expression tuple, so the
1695 * length will be a const.
1697 Expression
*e
= new IntegerExp(Loc(), ((TupleExp
*)ce
)->exps
->length
, Type::tsize_t
);
1698 v
= new VarDeclaration(loc
, Type::tsize_t
, Id::dollar
, new ExpInitializer(Loc(), e
));
1699 v
->storage_class
|= STCtemp
| STCstatic
| STCconst
;
1701 else if (ce
->type
&& (t
= ce
->type
->toBasetype()) != NULL
&&
1702 (t
->ty
== Tstruct
|| t
->ty
== Tclass
))
1704 // Look for opDollar
1705 assert(exp
->op
== TOKarray
|| exp
->op
== TOKslice
);
1706 AggregateDeclaration
*ad
= isAggregate(t
);
1709 Dsymbol
*s
= ad
->search(loc
, Id::opDollar
);
1710 if (!s
) // no dollar exists -- search in higher scope
1714 Expression
*e
= NULL
;
1715 // Check for multi-dimensional opDollar(dim) template.
1716 if (TemplateDeclaration
*td
= s
->isTemplateDeclaration())
1719 if (exp
->op
== TOKarray
)
1721 dim
= ((ArrayExp
*)exp
)->currentDimension
;
1723 else if (exp
->op
== TOKslice
)
1725 dim
= 0; // slices are currently always one-dimensional
1732 Objects
*tiargs
= new Objects();
1733 Expression
*edim
= new IntegerExp(Loc(), dim
, Type::tsize_t
);
1734 edim
= ::semantic(edim
, sc
);
1736 e
= new DotTemplateInstanceExp(loc
, ce
, td
->ident
, tiargs
);
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.
1745 if (exp
->op
== TOKarray
&& ((ArrayExp
*)exp
)->arguments
->length
!= 1)
1747 exp
->error("%s only defines opDollar for one dimension", ad
->toChars());
1750 Declaration
*d
= s
->isDeclaration();
1752 e
= new DotVarExp(loc
, ce
, d
);
1754 e
= ::semantic(e
, sc
);
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
;
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
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
1777 (*pvar
)->semantic(sc
);
1784 /****************************** DsymbolTable ******************************/
1786 DsymbolTable::DsymbolTable()
1791 Dsymbol
*DsymbolTable::lookup(Identifier
const * const ident
)
1793 //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
1794 return (Dsymbol
*)dmd_aaGetRvalue(tab
, const_cast<void *>((const void *)ident
));
1797 Dsymbol
*DsymbolTable::insert(Dsymbol
*s
)
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
);
1803 return NULL
; // already in table
1808 Dsymbol
*DsymbolTable::insert(Identifier
const * const ident
, Dsymbol
*s
)
1810 //printf("DsymbolTable::insert()\n");
1811 Dsymbol
**ps
= (Dsymbol
**)dmd_aaGet(&tab
, const_cast<void *>((const void *)ident
));
1813 return NULL
; // already in table
1818 Dsymbol
*DsymbolTable::update(Dsymbol
*s
)
1820 Identifier
*ident
= s
->ident
;
1821 Dsymbol
**ps
= (Dsymbol
**)dmd_aaGet(&tab
, (void *)ident
);
1826 /****************************** Prot ******************************/
1830 this->kind
= PROTundefined
;
1834 Prot::Prot(PROTKIND kind
)
1841 * Checks if `this` is superset of `other` restrictions.
1842 * For example, "protected" is more restrictive than "public".
1844 bool Prot::isMoreRestrictiveThan(const Prot other
) const
1846 return this->kind
< other
.kind
;
1850 * Checks if `this` is absolutely identical protection attribute to `other`
1852 bool Prot::operator==(const Prot
& other
) const
1854 if (this->kind
== other
.kind
)
1856 if (this->kind
== PROTpackage
)
1857 return this->pkg
== other
.pkg
;
1864 * Checks if parent defines different access restrictions than this one.
1867 * parent = protection attribute for scope that hosts this one
1870 * 'true' if parent is already more restrictive than this one and thus
1871 * no differentiation is needed.
1873 bool Prot::isSubsetOf(const Prot
& parent
) const
1875 if (this->kind
!= parent
.kind
)
1878 if (this->kind
== PROTpackage
)
1884 if (parent
.pkg
->isAncestorPackageOf(this->pkg
))