d: Merge upstream dmd 568496d5b, druntime 178c44ff, phobos 574bf883b.
[official-gcc.git] / gcc / d / dmd / dsymbol.d
blob9aa435d646381eea4c2ad874ebe247d9e107eda2
1 /**
2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
4 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d)
8 * Documentation: https://dlang.org/phobos/dmd_dsymbol.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d
12 module dmd.dsymbol;
14 import core.stdc.stdarg;
15 import core.stdc.stdio;
16 import core.stdc.string;
17 import core.stdc.stdlib;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arraytypes;
22 import dmd.attrib;
23 import dmd.astenums;
24 import dmd.ast_node;
25 import dmd.gluelayer;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dmodule;
31 import dmd.dversion;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbolsem;
35 import dmd.dtemplate;
36 import dmd.errors;
37 import dmd.expression;
38 import dmd.expressionsem;
39 import dmd.func;
40 import dmd.globals;
41 import dmd.id;
42 import dmd.identifier;
43 import dmd.init;
44 import dmd.lexer;
45 import dmd.mtype;
46 import dmd.nspace;
47 import dmd.opover;
48 import dmd.root.aav;
49 import dmd.root.rmem;
50 import dmd.root.rootobject;
51 import dmd.root.speller;
52 import dmd.root.string;
53 import dmd.statement;
54 import dmd.tokens;
55 import dmd.visitor;
57 /***************************************
58 * Calls dg(Dsymbol *sym) for each Dsymbol.
59 * If dg returns !=0, stops and returns that value else returns 0.
60 * Params:
61 * symbols = Dsymbols
62 * dg = delegate to call for each Dsymbol
63 * Returns:
64 * last value returned by dg()
66 * See_Also: $(REF each, dmd, root, array)
68 int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
70 assert(dg);
71 if (symbols)
73 /* Do not use foreach, as the size of the array may expand during iteration
75 for (size_t i = 0; i < symbols.dim; ++i)
77 Dsymbol s = (*symbols)[i];
78 const result = dg(s);
79 if (result)
80 return result;
83 return 0;
86 /***************************************
87 * Calls dg(Dsymbol *sym) for each Dsymbol.
88 * Params:
89 * symbols = Dsymbols
90 * dg = delegate to call for each Dsymbol
92 * See_Also: $(REF each, dmd, root, array)
94 void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
96 assert(dg);
97 if (symbols)
99 /* Do not use foreach, as the size of the array may expand during iteration
101 for (size_t i = 0; i < symbols.dim; ++i)
103 Dsymbol s = (*symbols)[i];
104 dg(s);
110 struct Ungag
112 uint oldgag;
114 extern (D) this(uint old)
116 this.oldgag = old;
119 extern (C++) ~this()
121 global.gag = oldgag;
125 struct Visibility
128 enum Kind : ubyte
130 undefined,
131 none, // no access
132 private_,
133 package_,
134 protected_,
135 public_,
136 export_,
139 Kind kind;
140 Package pkg;
142 extern (D):
144 this(Visibility.Kind kind) pure nothrow @nogc @safe
146 this.kind = kind;
150 * Checks if `this` is less or more visible than `other`
152 * Params:
153 * other = Visibility to compare `this` to.
155 * Returns:
156 * A value `< 0` if `this` is less visible than `other`,
157 * a value `> 0` if `this` is more visible than `other`,
158 * and `0` if they are at the same level.
159 * Note that `package` visibility with different packages
160 * will also return `0`.
162 int opCmp(const Visibility other) const pure nothrow @nogc @safe
164 return this.kind - other.kind;
168 unittest
170 assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_));
171 assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_));
172 assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_));
176 * Checks if `this` is absolutely identical visibility attribute to `other`
178 bool opEquals(ref const Visibility other) const
180 if (this.kind == other.kind)
182 if (this.kind == Visibility.Kind.package_)
183 return this.pkg == other.pkg;
184 return true;
186 return false;
190 enum PASS : ubyte
192 init, // initial state
193 semantic, // semantic() started
194 semanticdone, // semantic() done
195 semantic2, // semantic2() started
196 semantic2done, // semantic2() done
197 semantic3, // semantic3() started
198 semantic3done, // semantic3() done
199 inline, // inline started
200 inlinedone, // inline done
201 obj, // toObjFile() run
204 // Search options
205 enum : int
207 IgnoreNone = 0x00, // default
208 IgnorePrivateImports = 0x01, // don't search private imports
209 IgnoreErrors = 0x02, // don't give error messages
210 IgnoreAmbiguous = 0x04, // return NULL if ambiguous
211 SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
212 SearchImportsOnly = 0x10, // only look in imports
213 SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
214 // meaning don't search imports in that scope,
215 // because qualified module searches search
216 // their imports
217 IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
218 TagNameSpace = 0x100, // search ImportC tag symbol table
221 /***********************************************************
222 * Struct/Class/Union field state.
223 * Used for transitory information when setting field offsets, such
224 * as bit fields.
226 struct FieldState
228 uint offset; /// byte offset for next field
230 uint fieldOffset; /// byte offset for the start of the bit field
231 uint fieldSize; /// byte size of field
232 uint fieldAlign; /// byte alignment of field
233 uint bitOffset; /// bit offset for field
235 bool inFlight; /// bit field is in flight
238 /***********************************************************
240 extern (C++) class Dsymbol : ASTNode
242 Identifier ident;
243 Dsymbol parent;
244 /// C++ namespace this symbol belongs to
245 CPPNamespaceDeclaration cppnamespace;
246 Symbol* csym; // symbol for code generator
247 Symbol* isym; // import version of csym
248 const(char)* comment; // documentation comment for this Dsymbol
249 const Loc loc; // where defined
250 Scope* _scope; // !=null means context to use for semantic()
251 const(char)* prettystring; // cached value of toPrettyChars()
252 bool errors; // this symbol failed to pass semantic()
253 PASS semanticRun = PASS.init;
254 ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
256 DeprecatedDeclaration depdecl; // customized deprecation message
257 UserAttributeDeclaration userAttribDecl; // user defined attributes
259 // !=null means there's a ddoc unittest associated with this symbol
260 // (only use this with ddoc)
261 UnitTestDeclaration ddocUnittest;
263 final extern (D) this()
265 //printf("Dsymbol::Dsymbol(%p)\n", this);
266 loc = Loc(null, 0, 0);
269 final extern (D) this(Identifier ident)
271 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
272 this.loc = Loc(null, 0, 0);
273 this.ident = ident;
276 final extern (D) this(const ref Loc loc, Identifier ident)
278 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
279 this.loc = loc;
280 this.ident = ident;
283 static Dsymbol create(Identifier ident)
285 return new Dsymbol(ident);
288 override const(char)* toChars() const
290 return ident ? ident.toChars() : "__anonymous";
293 // helper to print fully qualified (template) arguments
294 const(char)* toPrettyCharsHelper()
296 return toChars();
299 final const(Loc) getLoc()
301 if (!loc.isValid()) // avoid bug 5861.
302 if (const m = getModule())
303 return Loc(m.srcfile.toChars(), 0, 0);
304 return loc;
307 final const(char)* locToChars()
309 return getLoc().toChars();
312 override bool equals(const RootObject o) const
314 if (this == o)
315 return true;
316 if (o.dyncast() != DYNCAST.dsymbol)
317 return false;
318 auto s = cast(Dsymbol)o;
319 // Overload sets don't have an ident
320 // Function-local declarations may have identical names
321 // if they are declared in different scopes
322 if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum)
323 return true;
324 return false;
327 final bool isAnonymous() const
329 return ident is null || ident.isAnonymous;
332 extern(D) private const(char)[] prettyFormatHelper()
334 const cstr = toPrettyChars();
335 return '`' ~ cstr.toDString() ~ "`\0";
338 static if (__VERSION__ < 2092)
340 final void error(const ref Loc loc, const(char)* format, ...)
342 va_list ap;
343 va_start(ap, format);
344 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
345 va_end(ap);
348 final void error(const(char)* format, ...)
350 va_list ap;
351 va_start(ap, format);
352 const loc = getLoc();
353 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
354 va_end(ap);
357 final void deprecation(const ref Loc loc, const(char)* format, ...)
359 va_list ap;
360 va_start(ap, format);
361 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
362 va_end(ap);
365 final void deprecation(const(char)* format, ...)
367 va_list ap;
368 va_start(ap, format);
369 const loc = getLoc();
370 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
371 va_end(ap);
374 else
376 pragma(printf) final void error(const ref Loc loc, const(char)* format, ...)
378 va_list ap;
379 va_start(ap, format);
380 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
381 va_end(ap);
384 pragma(printf) final void error(const(char)* format, ...)
386 va_list ap;
387 va_start(ap, format);
388 const loc = getLoc();
389 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
390 va_end(ap);
393 pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...)
395 va_list ap;
396 va_start(ap, format);
397 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
398 va_end(ap);
401 pragma(printf) final void deprecation(const(char)* format, ...)
403 va_list ap;
404 va_start(ap, format);
405 const loc = getLoc();
406 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
407 va_end(ap);
411 final bool checkDeprecated(const ref Loc loc, Scope* sc)
413 if (global.params.useDeprecated == DiagnosticReporting.off)
414 return false;
415 if (!this.isDeprecated())
416 return false;
417 // Don't complain if we're inside a deprecated symbol's scope
418 if (sc.isDeprecated())
419 return false;
420 // Don't complain if we're inside a template constraint
421 // https://issues.dlang.org/show_bug.cgi?id=21831
422 if (sc.flags & SCOPE.constraint)
423 return false;
425 const(char)* message = null;
426 for (Dsymbol p = this; p; p = p.parent)
428 message = p.depdecl ? p.depdecl.getMessage() : null;
429 if (message)
430 break;
432 if (message)
433 deprecation(loc, "is deprecated - %s", message);
434 else
435 deprecation(loc, "is deprecated");
437 if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
438 ti.printInstantiationTrace(Classification.deprecation);
439 else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
440 ti.printInstantiationTrace(Classification.deprecation);
442 return true;
445 /**********************************
446 * Determine which Module a Dsymbol is in.
448 final Module getModule()
450 //printf("Dsymbol::getModule()\n");
451 if (TemplateInstance ti = isInstantiated())
452 return ti.tempdecl.getModule();
453 Dsymbol s = this;
454 while (s)
456 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
457 Module m = s.isModule();
458 if (m)
459 return m;
460 s = s.parent;
462 return null;
465 /**********************************
466 * Determine which Module a Dsymbol is in, as far as access rights go.
468 final Module getAccessModule()
470 //printf("Dsymbol::getAccessModule()\n");
471 if (TemplateInstance ti = isInstantiated())
472 return ti.tempdecl.getAccessModule();
473 Dsymbol s = this;
474 while (s)
476 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
477 Module m = s.isModule();
478 if (m)
479 return m;
480 TemplateInstance ti = s.isTemplateInstance();
481 if (ti && ti.enclosing)
483 /* Because of local template instantiation, the parent isn't where the access
484 * rights come from - it's the template declaration
486 s = ti.tempdecl;
488 else
489 s = s.parent;
491 return null;
495 * `pastMixin` returns the enclosing symbol if this is a template mixin.
497 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
498 * are mangleOnly.
500 * See also `parent`, `toParent` and `toParent2`.
502 final inout(Dsymbol) pastMixin() inout
504 //printf("Dsymbol::pastMixin() %s\n", toChars());
505 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
506 return this;
507 if (!parent)
508 return null;
509 return parent.pastMixin();
512 /**********************************
513 * `parent` field returns a lexically enclosing scope symbol this is a member of.
515 * `toParent()` returns a logically enclosing scope symbol this is a member of.
516 * It skips over TemplateMixin's.
518 * `toParent2()` returns an enclosing scope symbol this is living at runtime.
519 * It skips over both TemplateInstance's and TemplateMixin's.
520 * It's used when looking for the 'this' pointer of the enclosing function/class.
522 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
523 * instead of the instantiation scope.
525 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
526 * if a template declaration is non-local i.e. global or static.
528 * Examples:
529 * ---
530 * module mod;
531 * template Foo(alias a) { mixin Bar!(); }
532 * mixin template Bar() {
533 * public { // VisibilityDeclaration
534 * void baz() { a = 2; }
537 * void test() {
538 * int v = 1;
539 * alias foo = Foo!(v);
540 * foo.baz();
541 * assert(v == 2);
544 * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
545 * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
546 * // s.toParent() == TemplateInstance('mod.test.Foo!()')
547 * // s.toParent2() == FuncDeclaration('mod.test')
548 * // s.toParentDecl() == Module('mod')
549 * // s.toParentLocal() == FuncDeclaration('mod.test')
550 * ---
552 final inout(Dsymbol) toParent() inout
554 return parent ? parent.pastMixin() : null;
557 /// ditto
558 final inout(Dsymbol) toParent2() inout
560 if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
561 return parent;
562 return parent.toParent2;
565 /// ditto
566 final inout(Dsymbol) toParentDecl() inout
568 return toParentDeclImpl(false);
571 /// ditto
572 final inout(Dsymbol) toParentLocal() inout
574 return toParentDeclImpl(true);
577 private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
579 auto p = toParent();
580 if (!p || !p.isTemplateInstance())
581 return p;
582 auto ti = p.isTemplateInstance();
583 if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
584 return ti.tempdecl.toParentDeclImpl(localOnly);
585 return parent.toParentDeclImpl(localOnly);
589 * Returns the declaration scope scope of `this` unless any of the symbols
590 * `p1` or `p2` resides in its enclosing instantiation scope then the
591 * latter is returned.
593 final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
595 return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
598 final inout(TemplateInstance) isInstantiated() inout
600 if (!parent)
601 return null;
602 auto ti = parent.isTemplateInstance();
603 if (ti && !ti.isTemplateMixin())
604 return ti;
605 return parent.isInstantiated();
608 /***
609 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
610 * instantiation scope of `this`.
612 final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
614 static bool has2This(Dsymbol s)
616 if (auto f = s.isFuncDeclaration())
617 return f.isThis2;
618 if (auto ad = s.isAggregateDeclaration())
619 return ad.vthis2 !is null;
620 return false;
623 if (has2This(this))
625 assert(p1);
626 auto outer = toParent();
627 while (outer)
629 auto ti = outer.isTemplateInstance();
630 if (!ti)
631 break;
632 foreach (oarg; *ti.tiargs)
634 auto sa = getDsymbol(oarg);
635 if (!sa)
636 continue;
637 sa = sa.toAlias().toParent2();
638 if (!sa)
639 continue;
640 if (sa == p1)
641 return true;
642 else if (p2 && sa == p2)
643 return true;
645 outer = ti.tempdecl.toParent();
647 return false;
649 return false;
652 // Check if this function is a member of a template which has only been
653 // instantiated speculatively, eg from inside is(typeof()).
654 // Return the speculative template instance it is part of,
655 // or NULL if not speculative.
656 final inout(TemplateInstance) isSpeculative() inout
658 if (!parent)
659 return null;
660 auto ti = parent.isTemplateInstance();
661 if (ti && ti.gagged)
662 return ti;
663 if (!parent.toParent())
664 return null;
665 return parent.isSpeculative();
668 final Ungag ungagSpeculative() const
670 uint oldgag = global.gag;
671 if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
672 global.gag = 0;
673 return Ungag(oldgag);
676 // kludge for template.isSymbol()
677 override final DYNCAST dyncast() const
679 return DYNCAST.dsymbol;
682 /*************************************
683 * Do syntax copy of an array of Dsymbol's.
685 extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
687 Dsymbols* b = null;
688 if (a)
690 b = a.copy();
691 for (size_t i = 0; i < b.dim; i++)
693 (*b)[i] = (*b)[i].syntaxCopy(null);
696 return b;
699 Identifier getIdent()
701 return ident;
704 const(char)* toPrettyChars(bool QualifyTypes = false)
706 if (prettystring && !QualifyTypes)
707 return prettystring;
709 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
710 if (!parent)
712 auto s = toChars();
713 if (!QualifyTypes)
714 prettystring = s;
715 return s;
718 // Computer number of components
719 size_t complength = 0;
720 for (Dsymbol p = this; p; p = p.parent)
721 ++complength;
723 // Allocate temporary array comp[]
724 alias T = const(char)[];
725 auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
726 auto comp = compptr[0 .. complength];
728 // Fill in comp[] and compute length of final result
729 size_t length = 0;
730 int i;
731 for (Dsymbol p = this; p; p = p.parent)
733 const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
734 const len = strlen(s);
735 comp[i] = s[0 .. len];
736 ++i;
737 length += len + 1;
740 auto s = cast(char*)mem.xmalloc_noscan(length);
741 auto q = s + length - 1;
742 *q = 0;
743 foreach (j; 0 .. complength)
745 const t = comp[j].ptr;
746 const len = comp[j].length;
747 q -= len;
748 memcpy(q, t, len);
749 if (q == s)
750 break;
751 *--q = '.';
753 free(comp.ptr);
754 if (!QualifyTypes)
755 prettystring = s;
756 return s;
759 const(char)* kind() const pure nothrow @nogc @safe
761 return "symbol";
764 /*********************************
765 * If this symbol is really an alias for another,
766 * return that other.
767 * If needed, semantic() is invoked due to resolve forward reference.
769 Dsymbol toAlias()
771 return this;
774 /*********************************
775 * Resolve recursive tuple expansion in eponymous template.
777 Dsymbol toAlias2()
779 return toAlias();
782 void addMember(Scope* sc, ScopeDsymbol sds)
784 //printf("Dsymbol::addMember('%s')\n", toChars());
785 //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
786 //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
787 parent = sds;
788 if (isAnonymous()) // no name, so can't add it to symbol table
789 return;
791 if (!sds.symtabInsert(this)) // if name is already defined
793 if (isAliasDeclaration() && !_scope)
794 setScope(sc);
795 Dsymbol s2 = sds.symtabLookup(this,ident);
797 // If using C tag/prototype/forward declaration rules
798 if (sc.flags & SCOPE.Cfile)
800 if (handleTagSymbols(*sc, this, s2, sds))
801 return;
802 if (handleSymbolRedeclarations(*sc, this, s2, sds))
803 return;
805 sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
806 errors = true;
807 return;
810 if (!s2.overloadInsert(this))
812 sds.multiplyDefined(Loc.initial, this, s2);
813 errors = true;
816 if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
818 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
820 error("`.%s` property cannot be redefined", ident.toChars());
821 errors = true;
826 /*************************************
827 * Set scope for future semantic analysis so we can
828 * deal better with forward references.
830 void setScope(Scope* sc)
832 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
833 if (!sc.nofree)
834 sc.setNoFree(); // may need it even after semantic() finishes
835 _scope = sc;
836 if (sc.depdecl)
837 depdecl = sc.depdecl;
838 if (!userAttribDecl)
839 userAttribDecl = sc.userAttribDecl;
842 void importAll(Scope* sc)
846 /*********************************************
847 * Search for ident as member of s.
848 * Params:
849 * loc = location to print for error messages
850 * ident = identifier to search for
851 * flags = IgnoreXXXX
852 * Returns:
853 * null if not found
855 Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
857 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
858 return null;
861 extern (D) final Dsymbol search_correct(Identifier ident)
863 /***************************************************
864 * Search for symbol with correct spelling.
866 extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
868 /* If not in the lexer's string table, it certainly isn't in the symbol table.
869 * Doing this first is a lot faster.
871 if (!seed.length)
872 return null;
873 Identifier id = Identifier.lookup(seed);
874 if (!id)
875 return null;
876 cost = 0; // all the same cost
877 Dsymbol s = this;
878 Module.clearCache();
879 return s.search(Loc.initial, id, IgnoreErrors);
882 if (global.gag)
883 return null; // don't do it for speculative compiles; too time consuming
884 // search for exact name first
885 if (auto s = search(Loc.initial, ident, IgnoreErrors))
886 return s;
887 return speller!symbol_search_fp(ident.toString());
890 /***************************************
891 * Search for identifier id as a member of `this`.
892 * `id` may be a template instance.
894 * Params:
895 * loc = location to print the error messages
896 * sc = the scope where the symbol is located
897 * id = the id of the symbol
898 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
900 * Returns:
901 * symbol found, NULL if not
903 extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
905 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
906 Dsymbol s = toAlias();
907 Dsymbol sm;
908 if (Declaration d = s.isDeclaration())
910 if (d.inuse)
912 .error(loc, "circular reference to `%s`", d.toPrettyChars());
913 return null;
916 switch (id.dyncast())
918 case DYNCAST.identifier:
919 sm = s.search(loc, cast(Identifier)id, flags);
920 break;
921 case DYNCAST.dsymbol:
923 // It's a template instance
924 //printf("\ttemplate instance id\n");
925 Dsymbol st = cast(Dsymbol)id;
926 TemplateInstance ti = st.isTemplateInstance();
927 sm = s.search(loc, ti.name);
928 if (!sm)
930 sm = s.search_correct(ti.name);
931 if (sm)
932 .error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
933 else
934 .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
935 return null;
937 sm = sm.toAlias();
938 TemplateDeclaration td = sm.isTemplateDeclaration();
939 if (!td)
941 .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
942 return null;
944 ti.tempdecl = td;
945 if (!ti.semanticRun)
946 ti.dsymbolSemantic(sc);
947 sm = ti.toAlias();
948 break;
950 case DYNCAST.type:
951 case DYNCAST.expression:
952 default:
953 assert(0);
955 return sm;
958 bool overloadInsert(Dsymbol s)
960 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
961 return false;
964 /*********************************
965 * Returns:
966 * SIZE_INVALID when the size cannot be determined
968 d_uns64 size(const ref Loc loc)
970 error("Dsymbol `%s` has no size", toChars());
971 return SIZE_INVALID;
974 bool isforwardRef()
976 return false;
979 // is a 'this' required to access the member
980 inout(AggregateDeclaration) isThis() inout
982 return null;
985 // is Dsymbol exported?
986 bool isExport() const
988 return false;
991 // is Dsymbol imported?
992 bool isImportedSymbol() const
994 return false;
997 // is Dsymbol deprecated?
998 bool isDeprecated() @safe @nogc pure nothrow const
1000 return false;
1003 bool isOverloadable() const
1005 return false;
1008 // is this a LabelDsymbol()?
1009 LabelDsymbol isLabel()
1011 return null;
1014 /// Returns an AggregateDeclaration when toParent() is that.
1015 final inout(AggregateDeclaration) isMember() inout
1017 //printf("Dsymbol::isMember() %s\n", toChars());
1018 auto p = toParent();
1019 //printf("parent is %s %s\n", p.kind(), p.toChars());
1020 return p ? p.isAggregateDeclaration() : null;
1023 /// Returns an AggregateDeclaration when toParent2() is that.
1024 final inout(AggregateDeclaration) isMember2() inout
1026 //printf("Dsymbol::isMember2() '%s'\n", toChars());
1027 auto p = toParent2();
1028 //printf("parent is %s %s\n", p.kind(), p.toChars());
1029 return p ? p.isAggregateDeclaration() : null;
1032 /// Returns an AggregateDeclaration when toParentDecl() is that.
1033 final inout(AggregateDeclaration) isMemberDecl() inout
1035 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1036 auto p = toParentDecl();
1037 //printf("parent is %s %s\n", p.kind(), p.toChars());
1038 return p ? p.isAggregateDeclaration() : null;
1041 /// Returns an AggregateDeclaration when toParentLocal() is that.
1042 final inout(AggregateDeclaration) isMemberLocal() inout
1044 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1045 auto p = toParentLocal();
1046 //printf("parent is %s %s\n", p.kind(), p.toChars());
1047 return p ? p.isAggregateDeclaration() : null;
1050 // is this a member of a ClassDeclaration?
1051 final ClassDeclaration isClassMember()
1053 auto ad = isMember();
1054 return ad ? ad.isClassDeclaration() : null;
1057 // is this a type?
1058 Type getType()
1060 return null;
1063 // need a 'this' pointer?
1064 bool needThis()
1066 return false;
1069 /*************************************
1071 Visibility visible() pure nothrow @nogc @safe
1073 return Visibility(Visibility.Kind.public_);
1076 /**************************************
1077 * Copy the syntax.
1078 * Used for template instantiations.
1079 * If s is NULL, allocate the new object, otherwise fill it in.
1081 Dsymbol syntaxCopy(Dsymbol s)
1083 printf("%s %s\n", kind(), toChars());
1084 assert(0);
1087 /**************************************
1088 * Determine if this symbol is only one.
1089 * Returns:
1090 * false, *ps = NULL: There are 2 or more symbols
1091 * true, *ps = NULL: There are zero symbols
1092 * true, *ps = symbol: The one and only one symbol
1094 bool oneMember(Dsymbol* ps, Identifier ident)
1096 //printf("Dsymbol::oneMember()\n");
1097 *ps = this;
1098 return true;
1101 /*****************************************
1102 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1104 extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
1106 //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1107 Dsymbol s = null;
1108 if (!members)
1110 *ps = null;
1111 return true;
1114 for (size_t i = 0; i < members.dim; i++)
1116 Dsymbol sx = (*members)[i];
1117 bool x = sx.oneMember(ps, ident);
1118 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1119 if (!x)
1121 //printf("\tfalse 1\n");
1122 assert(*ps is null);
1123 return false;
1125 if (*ps)
1127 assert(ident);
1128 if (!(*ps).ident || !(*ps).ident.equals(ident))
1129 continue;
1130 if (!s)
1131 s = *ps;
1132 else if (s.isOverloadable() && (*ps).isOverloadable())
1134 // keep head of overload set
1135 FuncDeclaration f1 = s.isFuncDeclaration();
1136 FuncDeclaration f2 = (*ps).isFuncDeclaration();
1137 if (f1 && f2)
1139 assert(!f1.isFuncAliasDeclaration());
1140 assert(!f2.isFuncAliasDeclaration());
1141 for (; f1 != f2; f1 = f1.overnext0)
1143 if (f1.overnext0 is null)
1145 f1.overnext0 = f2;
1146 break;
1151 else // more than one symbol
1153 *ps = null;
1154 //printf("\tfalse 2\n");
1155 return false;
1159 *ps = s; // s is the one symbol, null if none
1160 //printf("\ttrue\n");
1161 return true;
1164 void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
1168 /*****************************************
1169 * Is Dsymbol a variable that contains pointers?
1171 bool hasPointers()
1173 //printf("Dsymbol::hasPointers() %s\n", toChars());
1174 return false;
1177 bool hasStaticCtorOrDtor()
1179 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1180 return false;
1183 void addLocalClass(ClassDeclarations*)
1187 void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1191 void checkCtorConstInit()
1195 /****************************************
1196 * Add documentation comment to Dsymbol.
1197 * Ignore NULL comments.
1199 void addComment(const(char)* comment)
1201 //if (comment)
1202 // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
1203 if (!this.comment)
1204 this.comment = comment;
1205 else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
1207 // Concatenate the two
1208 this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true);
1212 /****************************************
1213 * Returns true if this symbol is defined in a non-root module without instantiation.
1215 final bool inNonRoot()
1217 Dsymbol s = parent;
1218 for (; s; s = s.toParent())
1220 if (auto ti = s.isTemplateInstance())
1222 return false;
1224 if (auto m = s.isModule())
1226 if (!m.isRoot())
1227 return true;
1228 break;
1231 return false;
1234 /************
1236 override void accept(Visitor v)
1238 v.visit(this);
1241 pure nothrow @safe @nogc:
1243 // Eliminate need for dynamic_cast
1244 inout(Package) isPackage() inout { return null; }
1245 inout(Module) isModule() inout { return null; }
1246 inout(EnumMember) isEnumMember() inout { return null; }
1247 inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
1248 inout(TemplateInstance) isTemplateInstance() inout { return null; }
1249 inout(TemplateMixin) isTemplateMixin() inout { return null; }
1250 inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
1251 inout(Nspace) isNspace() inout { return null; }
1252 inout(Declaration) isDeclaration() inout { return null; }
1253 inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
1254 inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
1255 inout(AliasAssign) isAliasAssign() inout { return null; }
1256 inout(ThisDeclaration) isThisDeclaration() inout { return null; }
1257 inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
1258 inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
1259 inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
1260 inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
1261 inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
1262 inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
1263 inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
1264 inout(OverDeclaration) isOverDeclaration() inout { return null; }
1265 inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
1266 inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
1267 inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
1268 inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
1269 inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
1270 inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
1271 inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
1272 inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
1273 inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
1274 inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
1275 inout(NewDeclaration) isNewDeclaration() inout { return null; }
1276 inout(VarDeclaration) isVarDeclaration() inout { return null; }
1277 inout(VersionSymbol) isVersionSymbol() inout { return null; }
1278 inout(DebugSymbol) isDebugSymbol() inout { return null; }
1279 inout(ClassDeclaration) isClassDeclaration() inout { return null; }
1280 inout(StructDeclaration) isStructDeclaration() inout { return null; }
1281 inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
1282 inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
1283 inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
1284 inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
1285 inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
1286 inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
1287 inout(Import) isImport() inout { return null; }
1288 inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
1289 inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
1290 inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
1291 inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
1292 inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
1293 inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
1294 inout(OverloadSet) isOverloadSet() inout { return null; }
1295 inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
1298 /***********************************************************
1299 * Dsymbol that generates a scope
1301 extern (C++) class ScopeDsymbol : Dsymbol
1303 Dsymbols* members; // all Dsymbol's in this scope
1304 DsymbolTable symtab; // members[] sorted into table
1305 uint endlinnum; // the linnumber of the statement after the scope (0 if unknown)
1307 private:
1308 /// symbols whose members have been imported, i.e. imported modules and template mixins
1309 Dsymbols* importedScopes;
1310 Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
1312 import dmd.root.bitarray;
1313 BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1315 public:
1316 final extern (D) this()
1320 final extern (D) this(Identifier ident)
1322 super(ident);
1325 final extern (D) this(const ref Loc loc, Identifier ident)
1327 super(loc, ident);
1330 override ScopeDsymbol syntaxCopy(Dsymbol s)
1332 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1333 ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1334 sds.comment = comment;
1335 sds.members = arraySyntaxCopy(members);
1336 sds.endlinnum = endlinnum;
1337 return sds;
1340 /*****************************************
1341 * This function is #1 on the list of functions that eat cpu time.
1342 * Be very, very careful about slowing it down.
1344 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1346 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1347 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1349 // Look in symbols declared in this module
1350 if (symtab && !(flags & SearchImportsOnly))
1352 //printf(" look in locals\n");
1353 auto s1 = symtab.lookup(ident);
1354 if (s1)
1356 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1357 return s1;
1360 //printf(" not found in locals\n");
1362 // Look in imported scopes
1363 if (!importedScopes)
1364 return null;
1366 //printf(" look in imports\n");
1367 Dsymbol s = null;
1368 OverloadSet a = null;
1369 // Look in imported modules
1370 for (size_t i = 0; i < importedScopes.dim; i++)
1372 // If private import, don't search it
1373 if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
1374 continue;
1375 int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
1376 Dsymbol ss = (*importedScopes)[i];
1377 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1379 if (ss.isModule())
1381 if (flags & SearchLocalsOnly)
1382 continue;
1384 else // mixin template
1386 if (flags & SearchImportsOnly)
1387 continue;
1389 sflags |= SearchLocalsOnly;
1392 /* Don't find private members if ss is a module
1394 Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1395 import dmd.access : symbolIsVisible;
1396 if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1397 continue;
1398 if (!s)
1400 s = s2;
1401 if (s && s.isOverloadSet())
1402 a = mergeOverloadSet(ident, a, s);
1404 else if (s2 && s != s2)
1406 if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1408 /* After following aliases, we found the same
1409 * symbol, so it's not an ambiguity. But if one
1410 * alias is deprecated or less accessible, prefer
1411 * the other.
1413 if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
1414 s = s2;
1416 else
1418 /* Two imports of the same module should be regarded as
1419 * the same.
1421 Import i1 = s.isImport();
1422 Import i2 = s2.isImport();
1423 if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1425 /* https://issues.dlang.org/show_bug.cgi?id=8668
1426 * Public selective import adds AliasDeclaration in module.
1427 * To make an overload set, resolve aliases in here and
1428 * get actual overload roots which accessible via s and s2.
1430 s = s.toAlias();
1431 s2 = s2.toAlias();
1432 /* If both s2 and s are overloadable (though we only
1433 * need to check s once)
1436 auto so2 = s2.isOverloadSet();
1437 if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
1439 if (symbolIsVisible(this, s2))
1441 a = mergeOverloadSet(ident, a, s2);
1443 if (!symbolIsVisible(this, s))
1444 s = s2;
1445 continue;
1448 /* Two different overflow sets can have the same members
1449 * https://issues.dlang.org/show_bug.cgi?id=16709
1451 auto so = s.isOverloadSet();
1452 if (so && so2)
1454 if (so.a.length == so2.a.length)
1456 foreach (j; 0 .. so.a.length)
1458 if (so.a[j] !is so2.a[j])
1459 goto L1;
1461 continue; // the same
1463 { } // different
1467 if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1468 return null;
1469 if (!(flags & IgnoreErrors))
1470 ScopeDsymbol.multiplyDefined(loc, s, s2);
1471 break;
1476 if (s)
1478 /* Build special symbol if we had multiple finds
1480 if (a)
1482 if (!s.isOverloadSet())
1483 a = mergeOverloadSet(ident, a, s);
1484 s = a;
1486 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1487 return s;
1489 //printf(" not found in imports\n");
1490 return null;
1493 extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1495 if (!os)
1497 os = new OverloadSet(ident);
1498 os.parent = this;
1500 if (OverloadSet os2 = s.isOverloadSet())
1502 // Merge the cross-module overload set 'os2' into 'os'
1503 if (os.a.dim == 0)
1505 os.a.setDim(os2.a.dim);
1506 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1508 else
1510 for (size_t i = 0; i < os2.a.dim; i++)
1512 os = mergeOverloadSet(ident, os, os2.a[i]);
1516 else
1518 assert(s.isOverloadable());
1519 /* Don't add to os[] if s is alias of previous sym
1521 for (size_t j = 0; j < os.a.dim; j++)
1523 Dsymbol s2 = os.a[j];
1524 if (s.toAlias() == s2.toAlias())
1526 if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
1528 os.a[j] = s;
1530 goto Lcontinue;
1533 os.push(s);
1534 Lcontinue:
1536 return os;
1539 void importScope(Dsymbol s, Visibility visibility)
1541 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1542 // No circular or redundant import's
1543 if (s != this)
1545 if (!importedScopes)
1546 importedScopes = new Dsymbols();
1547 else
1549 for (size_t i = 0; i < importedScopes.dim; i++)
1551 Dsymbol ss = (*importedScopes)[i];
1552 if (ss == s) // if already imported
1554 if (visibility.kind > visibilities[i])
1555 visibilities[i] = visibility.kind; // upgrade access
1556 return;
1560 importedScopes.push(s);
1561 visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.dim * (visibilities[0]).sizeof);
1562 visibilities[importedScopes.dim - 1] = visibility.kind;
1566 extern (D) final void addAccessiblePackage(Package p, Visibility visibility)
1568 auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1569 if (pary.length <= p.tag)
1570 pary.length = p.tag + 1;
1571 (*pary)[p.tag] = true;
1574 bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
1576 if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1577 visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1578 return true;
1579 foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1581 // only search visible scopes && imported modules should ignore private imports
1582 if (visibility.kind <= visibilities[i] &&
1583 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
1584 return true;
1586 return false;
1589 override final bool isforwardRef()
1591 return (members is null);
1594 static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1596 version (none)
1598 printf("ScopeDsymbol::multiplyDefined()\n");
1599 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1600 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1602 if (loc.isValid())
1604 .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
1605 s1.kind(), s1.toPrettyChars(), s1.locToChars(),
1606 s2.kind(), s2.toPrettyChars(), s2.locToChars());
1608 static if (0)
1610 if (auto so = s1.isOverloadSet())
1612 printf("first %p:\n", so);
1613 foreach (s; so.a[])
1615 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1618 if (auto so = s2.isOverloadSet())
1620 printf("second %p:\n", so);
1621 foreach (s; so.a[])
1623 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1628 else
1630 s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1634 override const(char)* kind() const
1636 return "ScopeDsymbol";
1639 /*******************************************
1640 * Look for member of the form:
1641 * const(MemberInfo)[] getMembers(string);
1642 * Returns NULL if not found
1644 final FuncDeclaration findGetMembers()
1646 Dsymbol s = search_function(this, Id.getmembers);
1647 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1648 version (none)
1650 // Finish
1651 __gshared TypeFunction tfgetmembers;
1652 if (!tfgetmembers)
1654 Scope sc;
1655 auto parameters = new Parameters();
1656 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1657 parameters.push(p);
1658 Type tret = null;
1659 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1660 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1662 if (fdx)
1663 fdx = fdx.overloadExactMatch(tfgetmembers);
1665 if (fdx && fdx.isVirtual())
1666 fdx = null;
1667 return fdx;
1670 /********************************
1671 * Insert Dsymbol in table.
1672 * Params:
1673 * s = symbol to add
1674 * Returns:
1675 * null if already in table, `s` if inserted
1677 Dsymbol symtabInsert(Dsymbol s)
1679 return symtab.insert(s);
1682 /****************************************
1683 * Look up identifier in symbol table.
1684 * Params:
1685 * s = symbol
1686 * id = identifier to look up
1687 * Returns:
1688 * Dsymbol if found, null if not
1690 Dsymbol symtabLookup(Dsymbol s, Identifier id)
1692 return symtab.lookup(id);
1695 /****************************************
1696 * Return true if any of the members are static ctors or static dtors, or if
1697 * any members have members that are.
1699 override bool hasStaticCtorOrDtor()
1701 if (members)
1703 for (size_t i = 0; i < members.dim; i++)
1705 Dsymbol member = (*members)[i];
1706 if (member.hasStaticCtorOrDtor())
1707 return true;
1710 return false;
1713 extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1715 /***************************************
1716 * Expands attribute declarations in members in depth first
1717 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1718 * member.
1719 * If dg returns !=0, stops and returns that value else returns 0.
1720 * Use this function to avoid the O(N + N^2/2) complexity of
1721 * calculating dim and calling N times getNth.
1722 * Returns:
1723 * last value returned by dg()
1725 extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1727 assert(dg);
1728 if (!members)
1729 return 0;
1730 size_t n = pn ? *pn : 0; // take over index
1731 int result = 0;
1732 foreach (size_t i; 0 .. members.dim)
1734 Dsymbol s = (*members)[i];
1735 if (AttribDeclaration a = s.isAttribDeclaration())
1736 result = _foreach(sc, a.include(sc), dg, &n);
1737 else if (TemplateMixin tm = s.isTemplateMixin())
1738 result = _foreach(sc, tm.members, dg, &n);
1739 else if (s.isTemplateInstance())
1742 else if (s.isUnitTestDeclaration())
1745 else
1746 result = dg(n++, s);
1747 if (result)
1748 break;
1750 if (pn)
1751 *pn = n; // update index
1752 return result;
1755 override final inout(ScopeDsymbol) isScopeDsymbol() inout
1757 return this;
1760 override void accept(Visitor v)
1762 v.visit(this);
1766 /***********************************************************
1767 * With statement scope
1769 extern (C++) final class WithScopeSymbol : ScopeDsymbol
1771 WithStatement withstate;
1773 extern (D) this(WithStatement withstate)
1775 this.withstate = withstate;
1778 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1780 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1781 if (flags & SearchImportsOnly)
1782 return null;
1783 // Acts as proxy to the with class declaration
1784 Dsymbol s = null;
1785 Expression eold = null;
1786 for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
1788 if (e.op == TOK.scope_)
1790 s = (cast(ScopeExp)e).sds;
1792 else if (e.op == TOK.type)
1794 s = e.type.toDsymbol(null);
1796 else
1798 Type t = e.type.toBasetype();
1799 s = t.toDsymbol(null);
1801 if (s)
1803 s = s.search(loc, ident, flags);
1804 if (s)
1805 return s;
1807 eold = e;
1809 return null;
1812 override inout(WithScopeSymbol) isWithScopeSymbol() inout
1814 return this;
1817 override void accept(Visitor v)
1819 v.visit(this);
1823 /***********************************************************
1824 * Array Index/Slice scope
1826 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1828 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1829 // Discriminated using DYNCAST and, for expressions, also TOK
1830 private RootObject arrayContent;
1831 Scope* sc;
1833 extern (D) this(Scope* sc, Expression exp)
1835 super(exp.loc, null);
1836 assert(exp.op == TOK.index || exp.op == TOK.slice || exp.op == TOK.array);
1837 this.sc = sc;
1838 this.arrayContent = exp;
1841 extern (D) this(Scope* sc, TypeTuple type)
1843 this.sc = sc;
1844 this.arrayContent = type;
1847 extern (D) this(Scope* sc, TupleDeclaration td)
1849 this.sc = sc;
1850 this.arrayContent = td;
1853 /// This override is used to solve `$`
1854 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
1856 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1857 if (ident != Id.dollar)
1858 return null;
1860 VarDeclaration* pvar;
1861 Expression ce;
1863 static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
1866 /* $ gives the number of type entries in the type tuple
1868 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1869 Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
1870 v._init = new ExpInitializer(Loc.initial, e);
1871 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1872 v.dsymbolSemantic(sc);
1873 return v;
1876 const DYNCAST kind = arrayContent.dyncast();
1877 if (kind == DYNCAST.dsymbol)
1879 TupleDeclaration td = cast(TupleDeclaration) arrayContent;
1880 /* $ gives the number of elements in the tuple
1882 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1883 Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
1884 v._init = new ExpInitializer(Loc.initial, e);
1885 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1886 v.dsymbolSemantic(sc);
1887 return v;
1889 if (kind == DYNCAST.type)
1891 return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
1893 Expression exp = cast(Expression) arrayContent;
1894 if (auto ie = exp.isIndexExp())
1896 /* array[index] where index is some function of $
1898 pvar = &ie.lengthVar;
1899 ce = ie.e1;
1901 else if (auto se = exp.isSliceExp())
1903 /* array[lwr .. upr] where lwr or upr is some function of $
1905 pvar = &se.lengthVar;
1906 ce = se.e1;
1908 else if (auto ae = exp.isArrayExp())
1910 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1911 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1913 pvar = &ae.lengthVar;
1914 ce = ae.e1;
1916 else
1918 /* Didn't find $, look in enclosing scope(s).
1920 return null;
1922 ce = ce.lastComma();
1923 /* If we are indexing into an array that is really a type
1924 * tuple, rewrite this as an index into a type tuple and
1925 * try again.
1927 if (auto te = ce.isTypeExp())
1929 if (auto ttp = te.type.isTypeTuple())
1930 return dollarFromTypeTuple(loc, ttp, sc);
1932 /* *pvar is lazily initialized, so if we refer to $
1933 * multiple times, it gets set only once.
1935 if (!*pvar) // if not already initialized
1937 /* Create variable v and set it to the value of $
1939 VarDeclaration v;
1940 Type t;
1941 if (auto tupexp = ce.isTupleExp())
1943 /* It is for an expression tuple, so the
1944 * length will be a const.
1946 Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
1947 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
1948 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1950 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
1952 // Look for opDollar
1953 assert(exp.op == TOK.array || exp.op == TOK.slice);
1954 AggregateDeclaration ad = isAggregate(t);
1955 assert(ad);
1956 Dsymbol s = ad.search(loc, Id.opDollar);
1957 if (!s) // no dollar exists -- search in higher scope
1958 return null;
1959 s = s.toAlias();
1960 Expression e = null;
1961 // Check for multi-dimensional opDollar(dim) template.
1962 if (TemplateDeclaration td = s.isTemplateDeclaration())
1964 dinteger_t dim = 0;
1965 if (exp.op == TOK.array)
1967 dim = (cast(ArrayExp)exp).currentDimension;
1969 else if (exp.op == TOK.slice)
1971 dim = 0; // slices are currently always one-dimensional
1973 else
1975 assert(0);
1977 auto tiargs = new Objects();
1978 Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
1979 edim = edim.expressionSemantic(sc);
1980 tiargs.push(edim);
1981 e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
1983 else
1985 /* opDollar exists, but it's not a template.
1986 * This is acceptable ONLY for single-dimension indexing.
1987 * Note that it's impossible to have both template & function opDollar,
1988 * because both take no arguments.
1990 if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1)
1992 exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
1993 return null;
1995 Declaration d = s.isDeclaration();
1996 assert(d);
1997 e = new DotVarExp(loc, ce, d);
1999 e = e.expressionSemantic(sc);
2000 if (!e.type)
2001 exp.error("`%s` has no value", e.toChars());
2002 t = e.type.toBasetype();
2003 if (t && t.ty == Tfunction)
2004 e = new CallExp(e.loc, e);
2005 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
2006 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
2008 else
2010 /* For arrays, $ will either be a compile-time constant
2011 * (in which case its value in set during constant-folding),
2012 * or a variable (in which case an expression is created in
2013 * toir.c).
2015 auto e = new VoidInitializer(Loc.initial);
2016 e.type = Type.tsize_t;
2017 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
2018 v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
2020 *pvar = v;
2022 (*pvar).dsymbolSemantic(sc);
2023 return (*pvar);
2026 override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
2028 return this;
2031 override void accept(Visitor v)
2033 v.visit(this);
2037 /***********************************************************
2038 * Overload Sets
2040 extern (C++) final class OverloadSet : Dsymbol
2042 Dsymbols a; // array of Dsymbols
2044 extern (D) this(Identifier ident, OverloadSet os = null)
2046 super(ident);
2047 if (os)
2049 a.pushSlice(os.a[]);
2053 void push(Dsymbol s)
2055 a.push(s);
2058 override inout(OverloadSet) isOverloadSet() inout
2060 return this;
2063 override const(char)* kind() const
2065 return "overloadset";
2068 override void accept(Visitor v)
2070 v.visit(this);
2074 /***********************************************************
2075 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2076 * ForwardingScopeDeclaration to forward symbol insertions to another
2077 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2078 * details.
2080 extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
2082 /*************************
2083 * Symbol to forward insertions to.
2084 * Can be `null` before being lazily initialized.
2086 ScopeDsymbol forward;
2087 extern (D) this(ScopeDsymbol forward)
2089 super(null);
2090 this.forward = forward;
2092 override Dsymbol symtabInsert(Dsymbol s)
2094 assert(forward);
2095 if (auto d = s.isDeclaration())
2097 if (d.storage_class & STC.local)
2099 // Symbols with storage class STC.local are not
2100 // forwarded, but stored in the local symbol
2101 // table. (Those are the `static foreach` variables.)
2102 if (!symtab)
2104 symtab = new DsymbolTable();
2106 return super.symtabInsert(s); // insert locally
2109 if (!forward.symtab)
2111 forward.symtab = new DsymbolTable();
2113 // Non-STC.local symbols are forwarded to `forward`.
2114 return forward.symtabInsert(s);
2117 /************************
2118 * This override handles the following two cases:
2119 * static foreach (i, i; [0]) { ... }
2120 * and
2121 * static foreach (i; [0]) { enum i = 2; }
2123 override Dsymbol symtabLookup(Dsymbol s, Identifier id)
2125 assert(forward);
2126 // correctly diagnose clashing foreach loop variables.
2127 if (auto d = s.isDeclaration())
2129 if (d.storage_class & STC.local)
2131 if (!symtab)
2133 symtab = new DsymbolTable();
2135 return super.symtabLookup(s,id);
2138 // Declarations within `static foreach` do not clash with
2139 // `static foreach` loop variables.
2140 if (!forward.symtab)
2142 forward.symtab = new DsymbolTable();
2144 return forward.symtabLookup(s,id);
2147 override void importScope(Dsymbol s, Visibility visibility)
2149 forward.importScope(s, visibility);
2152 override const(char)* kind()const{ return "local scope"; }
2154 override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
2156 return this;
2162 * Class that holds an expression in a Dsymbol wrapper.
2163 * This is not an AST node, but a class used to pass
2164 * an expression as a function parameter of type Dsymbol.
2166 extern (C++) final class ExpressionDsymbol : Dsymbol
2168 Expression exp;
2169 this(Expression exp)
2171 super();
2172 this.exp = exp;
2175 override inout(ExpressionDsymbol) isExpressionDsymbol() inout
2177 return this;
2181 /**********************************************
2182 * Encapsulate assigning to an alias:
2183 * `identifier = type;`
2184 * `identifier = symbol;`
2185 * where `identifier` is an AliasDeclaration in scope.
2187 extern (C++) final class AliasAssign : Dsymbol
2189 Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
2190 Type type; /// replace previous RHS of AliasDeclaration with `type`
2191 Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
2192 /// only one of type and aliassym can be != null
2194 extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym)
2196 super(loc, null);
2197 this.ident = ident;
2198 this.type = type;
2199 this.aliassym = aliassym;
2202 override AliasAssign syntaxCopy(Dsymbol s)
2204 assert(!s);
2205 AliasAssign aa = new AliasAssign(loc, ident,
2206 type ? type.syntaxCopy() : null,
2207 aliassym ? aliassym.syntaxCopy(null) : null);
2208 return aa;
2211 override inout(AliasAssign) isAliasAssign() inout
2213 return this;
2216 override const(char)* kind() const
2218 return "alias assignment";
2221 override void accept(Visitor v)
2223 v.visit(this);
2227 /***********************************************************
2228 * Table of Dsymbol's
2230 extern (C++) final class DsymbolTable : RootObject
2232 AssocArray!(Identifier, Dsymbol) tab;
2234 /***************************
2235 * Look up Identifier in symbol table
2236 * Params:
2237 * ident = identifer to look up
2238 * Returns:
2239 * Dsymbol if found, null if not
2241 Dsymbol lookup(const Identifier ident)
2243 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2244 return tab[ident];
2247 /**********
2248 * Replace existing symbol in symbol table with `s`.
2249 * If it's not there, add it.
2250 * Params:
2251 * s = replacement symbol with same identifier
2253 void update(Dsymbol s)
2255 *tab.getLvalue(s.ident) = s;
2258 /**************************
2259 * Insert Dsymbol in table.
2260 * Params:
2261 * s = symbol to add
2262 * Returns:
2263 * null if already in table, `s` if inserted
2265 Dsymbol insert(Dsymbol s)
2267 return insert(s.ident, s);
2270 /**************************
2271 * Insert Dsymbol in table.
2272 * Params:
2273 * ident = identifier to serve as index
2274 * s = symbol to add
2275 * Returns:
2276 * null if already in table, `s` if inserted
2278 Dsymbol insert(const Identifier ident, Dsymbol s)
2280 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2281 Dsymbol* ps = tab.getLvalue(ident);
2282 if (*ps)
2283 return null; // already in table
2284 *ps = s;
2285 return s;
2288 /*****************
2289 * Returns:
2290 * number of symbols in symbol table
2292 size_t length() const pure
2294 return tab.length;
2298 /**********************************************
2299 * ImportC tag symbols sit in a parallel symbol table,
2300 * so that this C code works:
2301 * ---
2302 * struct S { a; };
2303 * int S;
2304 * struct S s;
2305 * ---
2306 * But there are relatively few such tag symbols, so that would be
2307 * a waste of memory and complexity. An additional problem is we'd like the D side
2308 * to find the tag symbols with ordinary lookup, not lookup in both
2309 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2310 * The solution is to put the tag symbols that conflict into an associative
2311 * array, indexed by the address of the ordinary symbol that conflicts with it.
2312 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2313 * A side effect of our approach is that D code cannot access a tag symbol that is
2314 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2315 * has mentioned it when importing C headers. If someone wants to do it,
2316 * too bad so sad. Change the C code.
2317 * This function fixes up the symbol table when faced with adding a new symbol
2318 * `s` when there is an existing symbol `s2` with the same name.
2319 * C also allows forward and prototype declarations of tag symbols,
2320 * this function merges those.
2321 * Params:
2322 * sc = context
2323 * s = symbol to add to symbol table
2324 * s2 = existing declaration
2325 * sds = symbol table
2326 * Returns:
2327 * if s and s2 are successfully put in symbol table then return the merged symbol,
2328 * null if they conflict
2330 Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2332 enum log = false;
2333 if (log) printf("handleTagSymbols('%s')\n", s.toChars());
2334 auto sd = s.isScopeDsymbol(); // new declaration
2335 auto sd2 = s2.isScopeDsymbol(); // existing declaration
2337 if (!sd2)
2339 /* Look in tag table
2341 if (log) printf(" look in tag table\n");
2342 if (auto p = cast(void*)s2 in sc._module.tagSymTab)
2344 Dsymbol s2tag = *p;
2345 sd2 = s2tag.isScopeDsymbol();
2346 assert(sd2); // only tags allowed in tag symbol table
2350 if (sd && sd2) // `s` is a tag, `sd2` is the same tag
2352 if (log) printf(" tag is already defined\n");
2354 if (sd.kind() != sd2.kind()) // being enum/struct/union must match
2355 return null; // conflict
2357 /* Not a redeclaration if one is a forward declaration.
2358 * Move members to the first declared type, which is sd2.
2360 if (sd2.members)
2362 if (!sd.members)
2363 return sd2; // ignore the sd redeclaration
2365 else if (sd.members)
2367 sd2.members = sd.members; // transfer definition to sd2
2368 sd.members = null;
2369 return sd2;
2371 else
2372 return sd2; // ignore redeclaration
2374 else if (sd) // `s` is a tag, `s2` is not
2376 if (log) printf(" s is tag, s2 is not\n");
2377 /* add `s` as tag indexed by s2
2379 sc._module.tagSymTab[cast(void*)s2] = s;
2380 return s;
2382 else if (s2 is sd2) // `s2` is a tag, `s` is not
2384 if (log) printf(" s2 is tag, s is not\n");
2385 /* replace `s2` in symbol table with `s`,
2386 * then add `s2` as tag indexed by `s`
2388 sds.symtab.update(s);
2389 sc._module.tagSymTab[cast(void*)s] = s2;
2390 return s;
2392 if (log) printf(" collision\n");
2393 return null;
2397 /**********************************************
2398 * ImportC allows redeclarations of C variables, functions and typedefs.
2399 * extern int x;
2400 * int x = 3;
2401 * and:
2402 * extern void f();
2403 * void f() { }
2404 * Attempt to merge them.
2405 * Params:
2406 * sc = context
2407 * s = symbol to add to symbol table
2408 * s2 = existing declaration
2409 * sds = symbol table
2410 * Returns:
2411 * if s and s2 are successfully put in symbol table then return the merged symbol,
2412 * null if they conflict
2414 Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2416 enum log = false;
2417 if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
2419 static Dsymbol collision()
2421 if (log) printf(" collision\n");
2422 return null;
2425 auto vd = s.isVarDeclaration(); // new declaration
2426 auto vd2 = s2.isVarDeclaration(); // existing declaration
2427 if (vd && vd2)
2429 // if one is `static` and the other isn't
2430 if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
2431 return collision();
2433 const i1 = vd._init && ! vd._init.isVoidInitializer();
2434 const i2 = vd2._init && !vd2._init.isVoidInitializer();
2436 if (i1 && i2)
2437 return collision(); // can't both have initializers
2439 if (i1)
2440 return vd;
2442 /* BUG: the types should match, which needs semantic() to be run on it
2443 * extern int x;
2444 * int x; // match
2445 * typedef int INT;
2446 * INT x; // match
2447 * long x; // collision
2448 * We incorrectly ignore these collisions
2450 return vd2;
2453 auto fd = s.isFuncDeclaration(); // new declaration
2454 auto fd2 = s2.isFuncDeclaration(); // existing declaration
2455 if (fd && fd2)
2457 // if one is `static` and the other isn't
2458 if ((fd.storage_class ^ fd2.storage_class) & STC.static_)
2459 return collision();
2461 if (fd.fbody && fd2.fbody)
2462 return collision(); // can't both have bodies
2464 if (fd.fbody)
2465 return fd;
2467 /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2468 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2470 return fd2;
2473 auto td = s.isAliasDeclaration(); // new declaration
2474 auto td2 = s2.isAliasDeclaration(); // existing declaration
2475 if (td && td2)
2477 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2478 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2480 return td2;
2483 return collision();