d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
[official-gcc.git] / gcc / d / dmd / dsymbol.d
blob2021e2afd8e1e70fddfabe85ff06bf78255bfbb6
1 /**
2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
4 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://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.staticassert;
55 import dmd.tokens;
56 import dmd.visitor;
58 /***************************************
59 * Calls dg(Dsymbol *sym) for each Dsymbol.
60 * If dg returns !=0, stops and returns that value else returns 0.
61 * Params:
62 * symbols = Dsymbols
63 * dg = delegate to call for each Dsymbol
64 * Returns:
65 * last value returned by dg()
67 * See_Also: $(REF each, dmd, root, array)
69 int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
71 assert(dg);
72 if (symbols)
74 /* Do not use foreach, as the size of the array may expand during iteration
76 for (size_t i = 0; i < symbols.dim; ++i)
78 Dsymbol s = (*symbols)[i];
79 const result = dg(s);
80 if (result)
81 return result;
84 return 0;
87 /***************************************
88 * Calls dg(Dsymbol *sym) for each Dsymbol.
89 * Params:
90 * symbols = Dsymbols
91 * dg = delegate to call for each Dsymbol
93 * See_Also: $(REF each, dmd, root, array)
95 void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
97 assert(dg);
98 if (symbols)
100 /* Do not use foreach, as the size of the array may expand during iteration
102 for (size_t i = 0; i < symbols.dim; ++i)
104 Dsymbol s = (*symbols)[i];
105 dg(s);
111 struct Ungag
113 uint oldgag;
115 extern (D) this(uint old) nothrow
117 this.oldgag = old;
120 extern (C++) ~this() nothrow
122 global.gag = oldgag;
126 struct Visibility
129 enum Kind : ubyte
131 undefined,
132 none, // no access
133 private_,
134 package_,
135 protected_,
136 public_,
137 export_,
140 Kind kind;
141 Package pkg;
143 extern (D):
145 this(Visibility.Kind kind) pure nothrow @nogc @safe
147 this.kind = kind;
151 * Checks if `this` is less or more visible than `other`
153 * Params:
154 * other = Visibility to compare `this` to.
156 * Returns:
157 * A value `< 0` if `this` is less visible than `other`,
158 * a value `> 0` if `this` is more visible than `other`,
159 * and `0` if they are at the same level.
160 * Note that `package` visibility with different packages
161 * will also return `0`.
163 int opCmp(const Visibility other) const pure nothrow @nogc @safe
165 return this.kind - other.kind;
169 unittest
171 assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_));
172 assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_));
173 assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_));
177 * Checks if `this` is absolutely identical visibility attribute to `other`
179 bool opEquals(ref const Visibility other) const
181 if (this.kind == other.kind)
183 if (this.kind == Visibility.Kind.package_)
184 return this.pkg == other.pkg;
185 return true;
187 return false;
191 enum PASS : ubyte
193 initial, // initial state
194 semantic, // semantic() started
195 semanticdone, // semantic() done
196 semantic2, // semantic2() started
197 semantic2done, // semantic2() done
198 semantic3, // semantic3() started
199 semantic3done, // semantic3() done
200 inline, // inline started
201 inlinedone, // inline done
202 obj, // toObjFile() run
205 // Search options
206 enum : int
208 IgnoreNone = 0x00, // default
209 IgnorePrivateImports = 0x01, // don't search private imports
210 IgnoreErrors = 0x02, // don't give error messages
211 IgnoreAmbiguous = 0x04, // return NULL if ambiguous
212 SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
213 SearchImportsOnly = 0x10, // only look in imports
214 SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
215 // meaning don't search imports in that scope,
216 // because qualified module searches search
217 // their imports
218 IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
219 TagNameSpace = 0x100, // search ImportC tag symbol table
222 /***********************************************************
223 * Struct/Class/Union field state.
224 * Used for transitory information when setting field offsets, such
225 * as bit fields.
227 struct FieldState
229 uint offset; /// byte offset for next field
231 uint fieldOffset; /// byte offset for the start of the bit field
232 uint fieldSize; /// byte size of field
233 uint fieldAlign; /// byte alignment of field
234 uint bitOffset; /// bit offset for field
236 bool inFlight; /// bit field is in flight
239 /***********************************************************
241 extern (C++) class Dsymbol : ASTNode
243 Identifier ident;
244 Dsymbol parent;
245 /// C++ namespace this symbol belongs to
246 CPPNamespaceDeclaration cppnamespace;
247 Symbol* csym; // symbol for code generator
248 const Loc loc; // where defined
249 Scope* _scope; // !=null means context to use for semantic()
250 const(char)* prettystring; // cached value of toPrettyChars()
251 bool errors; // this symbol failed to pass semantic()
252 PASS semanticRun = PASS.initial;
253 ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
255 DeprecatedDeclaration depdecl; // customized deprecation message
256 UserAttributeDeclaration userAttribDecl; // user defined attributes
258 final extern (D) this() nothrow
260 //printf("Dsymbol::Dsymbol(%p)\n", this);
261 loc = Loc(null, 0, 0);
264 final extern (D) this(Identifier ident) nothrow
266 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
267 this.loc = Loc(null, 0, 0);
268 this.ident = ident;
271 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
273 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
274 this.loc = loc;
275 this.ident = ident;
278 static Dsymbol create(Identifier ident) nothrow
280 return new Dsymbol(ident);
283 override const(char)* toChars() const
285 return ident ? ident.toChars() : "__anonymous";
288 // helper to print fully qualified (template) arguments
289 const(char)* toPrettyCharsHelper()
291 return toChars();
294 final const(Loc) getLoc()
296 if (!loc.isValid()) // avoid bug 5861.
297 if (const m = getModule())
298 return Loc(m.srcfile.toChars(), 0, 0);
299 return loc;
302 final const(char)* locToChars()
304 return getLoc().toChars();
307 override bool equals(const RootObject o) const
309 if (this == o)
310 return true;
311 if (o.dyncast() != DYNCAST.dsymbol)
312 return false;
313 auto s = cast(Dsymbol)o;
314 // Overload sets don't have an ident
315 // Function-local declarations may have identical names
316 // if they are declared in different scopes
317 if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum)
318 return true;
319 return false;
322 final bool isAnonymous() const
324 return ident is null || ident.isAnonymous;
327 extern(D) private const(char)[] prettyFormatHelper()
329 const cstr = toPrettyChars();
330 return '`' ~ cstr.toDString() ~ "`\0";
333 static if (__VERSION__ < 2092)
335 final void error(const ref Loc loc, const(char)* format, ...)
337 va_list ap;
338 va_start(ap, format);
339 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
340 va_end(ap);
343 final void error(const(char)* format, ...)
345 va_list ap;
346 va_start(ap, format);
347 const loc = getLoc();
348 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
349 va_end(ap);
352 final void deprecation(const ref Loc loc, const(char)* format, ...)
354 va_list ap;
355 va_start(ap, format);
356 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
357 va_end(ap);
360 final void deprecation(const(char)* format, ...)
362 va_list ap;
363 va_start(ap, format);
364 const loc = getLoc();
365 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
366 va_end(ap);
369 else
371 pragma(printf) final void error(const ref Loc loc, const(char)* format, ...)
373 va_list ap;
374 va_start(ap, format);
375 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
376 va_end(ap);
379 pragma(printf) final void error(const(char)* format, ...)
381 va_list ap;
382 va_start(ap, format);
383 const loc = getLoc();
384 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
385 va_end(ap);
388 pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...)
390 va_list ap;
391 va_start(ap, format);
392 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
393 va_end(ap);
396 pragma(printf) final void deprecation(const(char)* format, ...)
398 va_list ap;
399 va_start(ap, format);
400 const loc = getLoc();
401 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
402 va_end(ap);
406 final bool checkDeprecated(const ref Loc loc, Scope* sc)
408 if (global.params.useDeprecated == DiagnosticReporting.off)
409 return false;
410 if (!this.isDeprecated())
411 return false;
412 // Don't complain if we're inside a deprecated symbol's scope
413 if (sc.isDeprecated())
414 return false;
415 // Don't complain if we're inside a template constraint
416 // https://issues.dlang.org/show_bug.cgi?id=21831
417 if (sc.flags & SCOPE.constraint)
418 return false;
420 const(char)* message = null;
421 for (Dsymbol p = this; p; p = p.parent)
423 message = p.depdecl ? p.depdecl.getMessage() : null;
424 if (message)
425 break;
427 if (message)
428 deprecation(loc, "is deprecated - %s", message);
429 else
430 deprecation(loc, "is deprecated");
432 if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
433 ti.printInstantiationTrace(Classification.deprecation);
434 else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
435 ti.printInstantiationTrace(Classification.deprecation);
437 return true;
440 /**********************************
441 * Determine which Module a Dsymbol is in.
443 final Module getModule()
445 //printf("Dsymbol::getModule()\n");
446 if (TemplateInstance ti = isInstantiated())
447 return ti.tempdecl.getModule();
448 Dsymbol s = this;
449 while (s)
451 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
452 Module m = s.isModule();
453 if (m)
454 return m;
455 s = s.parent;
457 return null;
460 /**************************************
461 * Does this Dsymbol come from a C file?
462 * Returns:
463 * true if it does
465 final bool isCsymbol()
467 if (Module m = getModule())
468 return m.filetype == FileType.c;
469 return false;
472 /**********************************
473 * Determine which Module a Dsymbol is in, as far as access rights go.
475 final Module getAccessModule()
477 //printf("Dsymbol::getAccessModule()\n");
478 if (TemplateInstance ti = isInstantiated())
479 return ti.tempdecl.getAccessModule();
480 Dsymbol s = this;
481 while (s)
483 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
484 Module m = s.isModule();
485 if (m)
486 return m;
487 TemplateInstance ti = s.isTemplateInstance();
488 if (ti && ti.enclosing)
490 /* Because of local template instantiation, the parent isn't where the access
491 * rights come from - it's the template declaration
493 s = ti.tempdecl;
495 else
496 s = s.parent;
498 return null;
502 * `pastMixin` returns the enclosing symbol if this is a template mixin.
504 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
505 * are mangleOnly.
507 * See also `parent`, `toParent` and `toParent2`.
509 final inout(Dsymbol) pastMixin() inout
511 //printf("Dsymbol::pastMixin() %s\n", toChars());
512 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
513 return this;
514 if (!parent)
515 return null;
516 return parent.pastMixin();
519 /**********************************
520 * `parent` field returns a lexically enclosing scope symbol this is a member of.
522 * `toParent()` returns a logically enclosing scope symbol this is a member of.
523 * It skips over TemplateMixin's.
525 * `toParent2()` returns an enclosing scope symbol this is living at runtime.
526 * It skips over both TemplateInstance's and TemplateMixin's.
527 * It's used when looking for the 'this' pointer of the enclosing function/class.
529 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
530 * instead of the instantiation scope.
532 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
533 * if a template declaration is non-local i.e. global or static.
535 * Examples:
536 * ---
537 * module mod;
538 * template Foo(alias a) { mixin Bar!(); }
539 * mixin template Bar() {
540 * public { // VisibilityDeclaration
541 * void baz() { a = 2; }
544 * void test() {
545 * int v = 1;
546 * alias foo = Foo!(v);
547 * foo.baz();
548 * assert(v == 2);
551 * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
552 * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
553 * // s.toParent() == TemplateInstance('mod.test.Foo!()')
554 * // s.toParent2() == FuncDeclaration('mod.test')
555 * // s.toParentDecl() == Module('mod')
556 * // s.toParentLocal() == FuncDeclaration('mod.test')
557 * ---
559 final inout(Dsymbol) toParent() inout
561 return parent ? parent.pastMixin() : null;
564 /// ditto
565 final inout(Dsymbol) toParent2() inout
567 if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
568 return parent;
569 return parent.toParent2;
572 /// ditto
573 final inout(Dsymbol) toParentDecl() inout
575 return toParentDeclImpl(false);
578 /// ditto
579 final inout(Dsymbol) toParentLocal() inout
581 return toParentDeclImpl(true);
584 private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
586 auto p = toParent();
587 if (!p || !p.isTemplateInstance())
588 return p;
589 auto ti = p.isTemplateInstance();
590 if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
591 return ti.tempdecl.toParentDeclImpl(localOnly);
592 return parent.toParentDeclImpl(localOnly);
596 * Returns the declaration scope scope of `this` unless any of the symbols
597 * `p1` or `p2` resides in its enclosing instantiation scope then the
598 * latter is returned.
600 final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
602 return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
605 final inout(TemplateInstance) isInstantiated() inout
607 if (!parent)
608 return null;
609 auto ti = parent.isTemplateInstance();
610 if (ti && !ti.isTemplateMixin())
611 return ti;
612 return parent.isInstantiated();
615 /***
616 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
617 * instantiation scope of `this`.
619 final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
621 static bool has2This(Dsymbol s)
623 if (auto f = s.isFuncDeclaration())
624 return f.hasDualContext();
625 if (auto ad = s.isAggregateDeclaration())
626 return ad.vthis2 !is null;
627 return false;
630 if (has2This(this))
632 assert(p1);
633 auto outer = toParent();
634 while (outer)
636 auto ti = outer.isTemplateInstance();
637 if (!ti)
638 break;
639 foreach (oarg; *ti.tiargs)
641 auto sa = getDsymbol(oarg);
642 if (!sa)
643 continue;
644 sa = sa.toAlias().toParent2();
645 if (!sa)
646 continue;
647 if (sa == p1)
648 return true;
649 else if (p2 && sa == p2)
650 return true;
652 outer = ti.tempdecl.toParent();
654 return false;
656 return false;
659 // Check if this function is a member of a template which has only been
660 // instantiated speculatively, eg from inside is(typeof()).
661 // Return the speculative template instance it is part of,
662 // or NULL if not speculative.
663 final inout(TemplateInstance) isSpeculative() inout
665 if (!parent)
666 return null;
667 auto ti = parent.isTemplateInstance();
668 if (ti && ti.gagged)
669 return ti;
670 if (!parent.toParent())
671 return null;
672 return parent.isSpeculative();
675 final Ungag ungagSpeculative() const
677 uint oldgag = global.gag;
678 if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
679 global.gag = 0;
680 return Ungag(oldgag);
683 // kludge for template.isSymbol()
684 override final DYNCAST dyncast() const
686 return DYNCAST.dsymbol;
689 /*************************************
690 * Do syntax copy of an array of Dsymbol's.
692 extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
694 Dsymbols* b = null;
695 if (a)
697 b = a.copy();
698 for (size_t i = 0; i < b.dim; i++)
700 (*b)[i] = (*b)[i].syntaxCopy(null);
703 return b;
706 Identifier getIdent()
708 return ident;
711 const(char)* toPrettyChars(bool QualifyTypes = false)
713 if (prettystring && !QualifyTypes)
714 return prettystring;
716 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
717 if (!parent)
719 auto s = toChars();
720 if (!QualifyTypes)
721 prettystring = s;
722 return s;
725 // Computer number of components
726 size_t complength = 0;
727 for (Dsymbol p = this; p; p = p.parent)
728 ++complength;
730 // Allocate temporary array comp[]
731 alias T = const(char)[];
732 auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
733 auto comp = compptr[0 .. complength];
735 // Fill in comp[] and compute length of final result
736 size_t length = 0;
737 int i;
738 for (Dsymbol p = this; p; p = p.parent)
740 const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
741 const len = strlen(s);
742 comp[i] = s[0 .. len];
743 ++i;
744 length += len + 1;
747 auto s = cast(char*)mem.xmalloc_noscan(length);
748 auto q = s + length - 1;
749 *q = 0;
750 foreach (j; 0 .. complength)
752 const t = comp[j].ptr;
753 const len = comp[j].length;
754 q -= len;
755 memcpy(q, t, len);
756 if (q == s)
757 break;
758 *--q = '.';
760 free(comp.ptr);
761 if (!QualifyTypes)
762 prettystring = s;
763 return s;
766 const(char)* kind() const pure nothrow @nogc @safe
768 return "symbol";
771 /*********************************
772 * If this symbol is really an alias for another,
773 * return that other.
774 * If needed, semantic() is invoked due to resolve forward reference.
776 Dsymbol toAlias()
778 return this;
781 /*********************************
782 * Resolve recursive tuple expansion in eponymous template.
784 Dsymbol toAlias2()
786 return toAlias();
789 void addMember(Scope* sc, ScopeDsymbol sds)
791 //printf("Dsymbol::addMember('%s')\n", toChars());
792 //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
793 //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
794 parent = sds;
795 if (isAnonymous()) // no name, so can't add it to symbol table
796 return;
798 if (!sds.symtabInsert(this)) // if name is already defined
800 if (isAliasDeclaration() && !_scope)
801 setScope(sc);
802 Dsymbol s2 = sds.symtabLookup(this,ident);
803 /* https://issues.dlang.org/show_bug.cgi?id=17434
805 * If we are trying to add an import to the symbol table
806 * that has already been introduced, then keep the one with
807 * larger visibility. This is fine for imports because if
808 * we have multiple imports of the same file, if a single one
809 * is public then the symbol is reachable.
811 if (auto i1 = isImport())
813 if (auto i2 = s2.isImport())
815 if (sc.explicitVisibility && sc.visibility > i2.visibility)
816 sds.symtab.update(this);
820 // If using C tag/prototype/forward declaration rules
821 if (sc.flags & SCOPE.Cfile && !this.isImport())
823 if (handleTagSymbols(*sc, this, s2, sds))
824 return;
825 if (handleSymbolRedeclarations(*sc, this, s2, sds))
826 return;
828 sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
829 errors = true;
830 return;
833 if (!s2.overloadInsert(this))
835 sds.multiplyDefined(Loc.initial, this, s2);
836 errors = true;
839 if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
841 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
843 error("`.%s` property cannot be redefined", ident.toChars());
844 errors = true;
849 /*************************************
850 * Set scope for future semantic analysis so we can
851 * deal better with forward references.
853 void setScope(Scope* sc)
855 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
856 if (!sc.nofree)
857 sc.setNoFree(); // may need it even after semantic() finishes
858 _scope = sc;
859 if (sc.depdecl)
860 depdecl = sc.depdecl;
861 if (!userAttribDecl)
862 userAttribDecl = sc.userAttribDecl;
865 void importAll(Scope* sc)
869 /*********************************************
870 * Search for ident as member of s.
871 * Params:
872 * loc = location to print for error messages
873 * ident = identifier to search for
874 * flags = IgnoreXXXX
875 * Returns:
876 * null if not found
878 Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
880 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
881 return null;
884 extern (D) final Dsymbol search_correct(Identifier ident)
886 /***************************************************
887 * Search for symbol with correct spelling.
889 extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
891 /* If not in the lexer's string table, it certainly isn't in the symbol table.
892 * Doing this first is a lot faster.
894 if (!seed.length)
895 return null;
896 Identifier id = Identifier.lookup(seed);
897 if (!id)
898 return null;
899 cost = 0; // all the same cost
900 Dsymbol s = this;
901 Module.clearCache();
902 return s.search(Loc.initial, id, IgnoreErrors);
905 if (global.gag)
906 return null; // don't do it for speculative compiles; too time consuming
907 // search for exact name first
908 if (auto s = search(Loc.initial, ident, IgnoreErrors))
909 return s;
910 return speller!symbol_search_fp(ident.toString());
913 /***************************************
914 * Search for identifier id as a member of `this`.
915 * `id` may be a template instance.
917 * Params:
918 * loc = location to print the error messages
919 * sc = the scope where the symbol is located
920 * id = the id of the symbol
921 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
923 * Returns:
924 * symbol found, NULL if not
926 extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
928 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
929 Dsymbol s = toAlias();
930 Dsymbol sm;
931 if (Declaration d = s.isDeclaration())
933 if (d.inuse)
935 .error(loc, "circular reference to `%s`", d.toPrettyChars());
936 return null;
939 switch (id.dyncast())
941 case DYNCAST.identifier:
942 sm = s.search(loc, cast(Identifier)id, flags);
943 break;
944 case DYNCAST.dsymbol:
946 // It's a template instance
947 //printf("\ttemplate instance id\n");
948 Dsymbol st = cast(Dsymbol)id;
949 TemplateInstance ti = st.isTemplateInstance();
950 sm = s.search(loc, ti.name);
951 if (!sm)
952 return null;
953 sm = sm.toAlias();
954 TemplateDeclaration td = sm.isTemplateDeclaration();
955 if (!td)
957 .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
958 return null;
960 ti.tempdecl = td;
961 if (!ti.semanticRun)
962 ti.dsymbolSemantic(sc);
963 sm = ti.toAlias();
964 break;
966 case DYNCAST.type:
967 case DYNCAST.expression:
968 default:
969 assert(0);
971 return sm;
974 bool overloadInsert(Dsymbol s)
976 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
977 return false;
980 /*********************************
981 * Returns:
982 * SIZE_INVALID when the size cannot be determined
984 uinteger_t size(const ref Loc loc)
986 error("Dsymbol `%s` has no size", toChars());
987 return SIZE_INVALID;
990 bool isforwardRef()
992 return false;
995 // is a 'this' required to access the member
996 inout(AggregateDeclaration) isThis() inout
998 return null;
1001 // is Dsymbol exported?
1002 bool isExport() const
1004 return false;
1007 // is Dsymbol imported?
1008 bool isImportedSymbol() const
1010 return false;
1013 // is Dsymbol deprecated?
1014 bool isDeprecated() @safe @nogc pure nothrow const
1016 return false;
1019 bool isOverloadable() const
1021 return false;
1024 // is this a LabelDsymbol()?
1025 LabelDsymbol isLabel()
1027 return null;
1030 /// Returns an AggregateDeclaration when toParent() is that.
1031 final inout(AggregateDeclaration) isMember() inout
1033 //printf("Dsymbol::isMember() %s\n", toChars());
1034 auto p = toParent();
1035 //printf("parent is %s %s\n", p.kind(), p.toChars());
1036 return p ? p.isAggregateDeclaration() : null;
1039 /// Returns an AggregateDeclaration when toParent2() is that.
1040 final inout(AggregateDeclaration) isMember2() inout
1042 //printf("Dsymbol::isMember2() '%s'\n", toChars());
1043 auto p = toParent2();
1044 //printf("parent is %s %s\n", p.kind(), p.toChars());
1045 return p ? p.isAggregateDeclaration() : null;
1048 /// Returns an AggregateDeclaration when toParentDecl() is that.
1049 final inout(AggregateDeclaration) isMemberDecl() inout
1051 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1052 auto p = toParentDecl();
1053 //printf("parent is %s %s\n", p.kind(), p.toChars());
1054 return p ? p.isAggregateDeclaration() : null;
1057 /// Returns an AggregateDeclaration when toParentLocal() is that.
1058 final inout(AggregateDeclaration) isMemberLocal() inout
1060 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1061 auto p = toParentLocal();
1062 //printf("parent is %s %s\n", p.kind(), p.toChars());
1063 return p ? p.isAggregateDeclaration() : null;
1066 // is this a member of a ClassDeclaration?
1067 final ClassDeclaration isClassMember()
1069 auto ad = isMember();
1070 return ad ? ad.isClassDeclaration() : null;
1073 // is this a type?
1074 Type getType()
1076 return null;
1079 // need a 'this' pointer?
1080 bool needThis()
1082 return false;
1085 /*************************************
1087 Visibility visible() pure nothrow @nogc @safe
1089 return Visibility(Visibility.Kind.public_);
1092 /**************************************
1093 * Copy the syntax.
1094 * Used for template instantiations.
1095 * If s is NULL, allocate the new object, otherwise fill it in.
1097 Dsymbol syntaxCopy(Dsymbol s)
1099 printf("%s %s\n", kind(), toChars());
1100 assert(0);
1103 /**************************************
1104 * Determine if this symbol is only one.
1105 * Returns:
1106 * false, *ps = NULL: There are 2 or more symbols
1107 * true, *ps = NULL: There are zero symbols
1108 * true, *ps = symbol: The one and only one symbol
1110 bool oneMember(Dsymbol* ps, Identifier ident)
1112 //printf("Dsymbol::oneMember()\n");
1113 *ps = this;
1114 return true;
1117 /*****************************************
1118 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1120 extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
1122 //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1123 Dsymbol s = null;
1124 if (!members)
1126 *ps = null;
1127 return true;
1130 for (size_t i = 0; i < members.dim; i++)
1132 Dsymbol sx = (*members)[i];
1133 bool x = sx.oneMember(ps, ident);
1134 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1135 if (!x)
1137 //printf("\tfalse 1\n");
1138 assert(*ps is null);
1139 return false;
1141 if (*ps)
1143 assert(ident);
1144 if (!(*ps).ident || !(*ps).ident.equals(ident))
1145 continue;
1146 if (!s)
1147 s = *ps;
1148 else if (s.isOverloadable() && (*ps).isOverloadable())
1150 // keep head of overload set
1151 FuncDeclaration f1 = s.isFuncDeclaration();
1152 FuncDeclaration f2 = (*ps).isFuncDeclaration();
1153 if (f1 && f2)
1155 assert(!f1.isFuncAliasDeclaration());
1156 assert(!f2.isFuncAliasDeclaration());
1157 for (; f1 != f2; f1 = f1.overnext0)
1159 if (f1.overnext0 is null)
1161 f1.overnext0 = f2;
1162 break;
1167 else // more than one symbol
1169 *ps = null;
1170 //printf("\tfalse 2\n");
1171 return false;
1175 *ps = s; // s is the one symbol, null if none
1176 //printf("\ttrue\n");
1177 return true;
1180 void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
1184 /*****************************************
1185 * Is Dsymbol a variable that contains pointers?
1187 bool hasPointers()
1189 //printf("Dsymbol::hasPointers() %s\n", toChars());
1190 return false;
1193 bool hasStaticCtorOrDtor()
1195 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1196 return false;
1199 void addLocalClass(ClassDeclarations*)
1203 void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1207 void checkCtorConstInit()
1211 /****************************************
1212 * Add documentation comment to Dsymbol.
1213 * Ignore NULL comments.
1215 void addComment(const(char)* comment)
1217 if (!comment || !*comment)
1218 return;
1220 //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
1221 void* h = cast(void*)this; // just the pointer is the key
1222 auto p = h in commentHashTable;
1223 if (!p)
1225 commentHashTable[h] = comment;
1226 return;
1228 if (strcmp(*p, comment) != 0)
1230 // Concatenate the two
1231 *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
1235 /// get documentation comment for this Dsymbol
1236 final const(char)* comment()
1238 //printf("getcomment: %p '%s'\n", this, this.toChars());
1239 if (auto p = cast(void*)this in commentHashTable)
1241 //printf("comment: '%s'\n", *p);
1242 return *p;
1244 return null;
1247 /* Shell around addComment() to avoid disruption for the moment */
1248 final void comment(const(char)* comment) { addComment(comment); }
1250 private extern (D) __gshared const(char)*[void*] commentHashTable;
1253 /**********************************
1254 * Get ddoc unittest associated with this symbol.
1255 * (only use this with ddoc)
1256 * Returns: ddoc unittest, null if none
1258 final UnitTestDeclaration ddocUnittest()
1260 if (auto p = cast(void*)this in ddocUnittestHashTable)
1261 return *p;
1262 return null;
1265 /**********************************
1266 * Set ddoc unittest associated with this symbol.
1268 final void ddocUnittest(UnitTestDeclaration utd)
1270 ddocUnittestHashTable[cast(void*)this] = utd;
1273 private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable;
1276 /****************************************
1277 * Returns true if this symbol is defined in a non-root module without instantiation.
1279 final bool inNonRoot()
1281 Dsymbol s = parent;
1282 for (; s; s = s.toParent())
1284 if (auto ti = s.isTemplateInstance())
1286 return false;
1288 if (auto m = s.isModule())
1290 if (!m.isRoot())
1291 return true;
1292 break;
1295 return false;
1299 * Deinitializes the global state of the compiler.
1301 * This can be used to restore the state set by `_init` to its original
1302 * state.
1304 static void deinitialize()
1306 commentHashTable = commentHashTable.init;
1307 ddocUnittestHashTable = ddocUnittestHashTable.init;
1310 /************
1312 override void accept(Visitor v)
1314 v.visit(this);
1317 pure nothrow @safe @nogc:
1319 // Eliminate need for dynamic_cast
1320 inout(Package) isPackage() inout { return null; }
1321 inout(Module) isModule() inout { return null; }
1322 inout(EnumMember) isEnumMember() inout { return null; }
1323 inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
1324 inout(TemplateInstance) isTemplateInstance() inout { return null; }
1325 inout(TemplateMixin) isTemplateMixin() inout { return null; }
1326 inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
1327 inout(Nspace) isNspace() inout { return null; }
1328 inout(Declaration) isDeclaration() inout { return null; }
1329 inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
1330 inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
1331 inout(AliasAssign) isAliasAssign() inout { return null; }
1332 inout(ThisDeclaration) isThisDeclaration() inout { return null; }
1333 inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
1334 inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
1335 inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
1336 inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
1337 inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
1338 inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
1339 inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
1340 inout(OverDeclaration) isOverDeclaration() inout { return null; }
1341 inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
1342 inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
1343 inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
1344 inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
1345 inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
1346 inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
1347 inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
1348 inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
1349 inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
1350 inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
1351 inout(NewDeclaration) isNewDeclaration() inout { return null; }
1352 inout(VarDeclaration) isVarDeclaration() inout { return null; }
1353 inout(VersionSymbol) isVersionSymbol() inout { return null; }
1354 inout(DebugSymbol) isDebugSymbol() inout { return null; }
1355 inout(ClassDeclaration) isClassDeclaration() inout { return null; }
1356 inout(StructDeclaration) isStructDeclaration() inout { return null; }
1357 inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
1358 inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
1359 inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
1360 inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
1361 inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
1362 inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
1363 inout(Import) isImport() inout { return null; }
1364 inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
1365 inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
1366 inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
1367 inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
1368 inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
1369 inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
1370 inout(OverloadSet) isOverloadSet() inout { return null; }
1371 inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
1372 inout(StaticAssert) isStaticAssert() inout { return null; }
1375 /***********************************************************
1376 * Dsymbol that generates a scope
1378 extern (C++) class ScopeDsymbol : Dsymbol
1380 Dsymbols* members; // all Dsymbol's in this scope
1381 DsymbolTable symtab; // members[] sorted into table
1382 uint endlinnum; // the linnumber of the statement after the scope (0 if unknown)
1384 private:
1385 /// symbols whose members have been imported, i.e. imported modules and template mixins
1386 Dsymbols* importedScopes;
1387 Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
1389 import dmd.root.bitarray;
1390 BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1392 public:
1393 final extern (D) this() nothrow
1397 final extern (D) this(Identifier ident) nothrow
1399 super(ident);
1402 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
1404 super(loc, ident);
1407 override ScopeDsymbol syntaxCopy(Dsymbol s)
1409 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1410 ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1411 sds.comment = comment;
1412 sds.members = arraySyntaxCopy(members);
1413 sds.endlinnum = endlinnum;
1414 return sds;
1417 /*****************************************
1418 * This function is #1 on the list of functions that eat cpu time.
1419 * Be very, very careful about slowing it down.
1421 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1423 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1424 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1426 // Look in symbols declared in this module
1427 if (symtab && !(flags & SearchImportsOnly))
1429 //printf(" look in locals\n");
1430 auto s1 = symtab.lookup(ident);
1431 if (s1)
1433 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1434 return s1;
1437 //printf(" not found in locals\n");
1439 // Look in imported scopes
1440 if (!importedScopes)
1441 return null;
1443 //printf(" look in imports\n");
1444 Dsymbol s = null;
1445 OverloadSet a = null;
1446 // Look in imported modules
1447 for (size_t i = 0; i < importedScopes.dim; i++)
1449 // If private import, don't search it
1450 if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
1451 continue;
1452 int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
1453 Dsymbol ss = (*importedScopes)[i];
1454 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1456 if (ss.isModule())
1458 if (flags & SearchLocalsOnly)
1459 continue;
1461 else // mixin template
1463 if (flags & SearchImportsOnly)
1464 continue;
1466 sflags |= SearchLocalsOnly;
1469 /* Don't find private members if ss is a module
1471 Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1472 import dmd.access : symbolIsVisible;
1473 if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1474 continue;
1475 if (!s)
1477 s = s2;
1478 if (s && s.isOverloadSet())
1479 a = mergeOverloadSet(ident, a, s);
1481 else if (s2 && s != s2)
1483 if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1485 /* After following aliases, we found the same
1486 * symbol, so it's not an ambiguity. But if one
1487 * alias is deprecated or less accessible, prefer
1488 * the other.
1490 if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
1491 s = s2;
1493 else
1495 /* Two imports of the same module should be regarded as
1496 * the same.
1498 Import i1 = s.isImport();
1499 Import i2 = s2.isImport();
1500 if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1502 /* https://issues.dlang.org/show_bug.cgi?id=8668
1503 * Public selective import adds AliasDeclaration in module.
1504 * To make an overload set, resolve aliases in here and
1505 * get actual overload roots which accessible via s and s2.
1507 s = s.toAlias();
1508 s2 = s2.toAlias();
1509 /* If both s2 and s are overloadable (though we only
1510 * need to check s once)
1513 auto so2 = s2.isOverloadSet();
1514 if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
1516 if (symbolIsVisible(this, s2))
1518 a = mergeOverloadSet(ident, a, s2);
1520 if (!symbolIsVisible(this, s))
1521 s = s2;
1522 continue;
1525 /* Two different overflow sets can have the same members
1526 * https://issues.dlang.org/show_bug.cgi?id=16709
1528 auto so = s.isOverloadSet();
1529 if (so && so2)
1531 if (so.a.length == so2.a.length)
1533 foreach (j; 0 .. so.a.length)
1535 if (so.a[j] !is so2.a[j])
1536 goto L1;
1538 continue; // the same
1540 { } // different
1544 if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1545 return null;
1546 if (!(flags & IgnoreErrors))
1547 ScopeDsymbol.multiplyDefined(loc, s, s2);
1548 break;
1553 if (s)
1555 /* Build special symbol if we had multiple finds
1557 if (a)
1559 if (!s.isOverloadSet())
1560 a = mergeOverloadSet(ident, a, s);
1561 s = a;
1563 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1564 return s;
1566 //printf(" not found in imports\n");
1567 return null;
1570 extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1572 if (!os)
1574 os = new OverloadSet(ident);
1575 os.parent = this;
1577 if (OverloadSet os2 = s.isOverloadSet())
1579 // Merge the cross-module overload set 'os2' into 'os'
1580 if (os.a.dim == 0)
1582 os.a.setDim(os2.a.dim);
1583 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1585 else
1587 for (size_t i = 0; i < os2.a.dim; i++)
1589 os = mergeOverloadSet(ident, os, os2.a[i]);
1593 else
1595 assert(s.isOverloadable());
1596 /* Don't add to os[] if s is alias of previous sym
1598 for (size_t j = 0; j < os.a.dim; j++)
1600 Dsymbol s2 = os.a[j];
1601 if (s.toAlias() == s2.toAlias())
1603 if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
1605 os.a[j] = s;
1607 goto Lcontinue;
1610 os.push(s);
1611 Lcontinue:
1613 return os;
1616 void importScope(Dsymbol s, Visibility visibility) nothrow
1618 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1619 // No circular or redundant import's
1620 if (s != this)
1622 if (!importedScopes)
1623 importedScopes = new Dsymbols();
1624 else
1626 for (size_t i = 0; i < importedScopes.dim; i++)
1628 Dsymbol ss = (*importedScopes)[i];
1629 if (ss == s) // if already imported
1631 if (visibility.kind > visibilities[i])
1632 visibilities[i] = visibility.kind; // upgrade access
1633 return;
1637 importedScopes.push(s);
1638 visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.dim * (visibilities[0]).sizeof);
1639 visibilities[importedScopes.dim - 1] = visibility.kind;
1643 extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
1645 auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1646 if (pary.length <= p.tag)
1647 pary.length = p.tag + 1;
1648 (*pary)[p.tag] = true;
1651 bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
1653 if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1654 visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1655 return true;
1656 foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1658 // only search visible scopes && imported modules should ignore private imports
1659 if (visibility.kind <= visibilities[i] &&
1660 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
1661 return true;
1663 return false;
1666 override final bool isforwardRef() nothrow
1668 return (members is null);
1671 static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1673 version (none)
1675 printf("ScopeDsymbol::multiplyDefined()\n");
1676 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1677 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1679 if (loc.isValid())
1681 .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
1682 s1.kind(), s1.toPrettyChars(), s1.locToChars(),
1683 s2.kind(), s2.toPrettyChars(), s2.locToChars());
1685 static if (0)
1687 if (auto so = s1.isOverloadSet())
1689 printf("first %p:\n", so);
1690 foreach (s; so.a[])
1692 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1695 if (auto so = s2.isOverloadSet())
1697 printf("second %p:\n", so);
1698 foreach (s; so.a[])
1700 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1705 else
1707 s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1711 override const(char)* kind() const
1713 return "ScopeDsymbol";
1716 /*******************************************
1717 * Look for member of the form:
1718 * const(MemberInfo)[] getMembers(string);
1719 * Returns NULL if not found
1721 final FuncDeclaration findGetMembers()
1723 Dsymbol s = search_function(this, Id.getmembers);
1724 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1725 version (none)
1727 // Finish
1728 __gshared TypeFunction tfgetmembers;
1729 if (!tfgetmembers)
1731 Scope sc;
1732 auto parameters = new Parameters();
1733 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1734 parameters.push(p);
1735 Type tret = null;
1736 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1737 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1739 if (fdx)
1740 fdx = fdx.overloadExactMatch(tfgetmembers);
1742 if (fdx && fdx.isVirtual())
1743 fdx = null;
1744 return fdx;
1747 /********************************
1748 * Insert Dsymbol in table.
1749 * Params:
1750 * s = symbol to add
1751 * Returns:
1752 * null if already in table, `s` if inserted
1754 Dsymbol symtabInsert(Dsymbol s) nothrow
1756 return symtab.insert(s);
1759 /****************************************
1760 * Look up identifier in symbol table.
1761 * Params:
1762 * s = symbol
1763 * id = identifier to look up
1764 * Returns:
1765 * Dsymbol if found, null if not
1767 Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
1769 return symtab.lookup(id);
1772 /****************************************
1773 * Return true if any of the members are static ctors or static dtors, or if
1774 * any members have members that are.
1776 override bool hasStaticCtorOrDtor()
1778 if (members)
1780 for (size_t i = 0; i < members.dim; i++)
1782 Dsymbol member = (*members)[i];
1783 if (member.hasStaticCtorOrDtor())
1784 return true;
1787 return false;
1790 extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1792 /***************************************
1793 * Expands attribute declarations in members in depth first
1794 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1795 * member.
1796 * If dg returns !=0, stops and returns that value else returns 0.
1797 * Use this function to avoid the O(N + N^2/2) complexity of
1798 * calculating dim and calling N times getNth.
1799 * Returns:
1800 * last value returned by dg()
1802 extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1804 assert(dg);
1805 if (!members)
1806 return 0;
1807 size_t n = pn ? *pn : 0; // take over index
1808 int result = 0;
1809 foreach (size_t i; 0 .. members.dim)
1811 Dsymbol s = (*members)[i];
1812 if (AttribDeclaration a = s.isAttribDeclaration())
1813 result = _foreach(sc, a.include(sc), dg, &n);
1814 else if (TemplateMixin tm = s.isTemplateMixin())
1815 result = _foreach(sc, tm.members, dg, &n);
1816 else if (s.isTemplateInstance())
1819 else if (s.isUnitTestDeclaration())
1822 else
1823 result = dg(n++, s);
1824 if (result)
1825 break;
1827 if (pn)
1828 *pn = n; // update index
1829 return result;
1832 override final inout(ScopeDsymbol) isScopeDsymbol() inout
1834 return this;
1837 override void accept(Visitor v)
1839 v.visit(this);
1843 /***********************************************************
1844 * With statement scope
1846 extern (C++) final class WithScopeSymbol : ScopeDsymbol
1848 WithStatement withstate;
1850 extern (D) this(WithStatement withstate) nothrow
1852 this.withstate = withstate;
1855 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1857 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1858 if (flags & SearchImportsOnly)
1859 return null;
1860 // Acts as proxy to the with class declaration
1861 Dsymbol s = null;
1862 Expression eold = null;
1863 for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
1865 if (e.op == EXP.scope_)
1867 s = (cast(ScopeExp)e).sds;
1869 else if (e.op == EXP.type)
1871 s = e.type.toDsymbol(null);
1873 else
1875 Type t = e.type.toBasetype();
1876 s = t.toDsymbol(null);
1878 if (s)
1880 s = s.search(loc, ident, flags);
1881 if (s)
1882 return s;
1884 eold = e;
1886 return null;
1889 override inout(WithScopeSymbol) isWithScopeSymbol() inout
1891 return this;
1894 override void accept(Visitor v)
1896 v.visit(this);
1900 /***********************************************************
1901 * Array Index/Slice scope
1903 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1905 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1906 // Discriminated using DYNCAST and, for expressions, also EXP
1907 private RootObject arrayContent;
1908 Scope* sc;
1910 extern (D) this(Scope* sc, Expression exp) nothrow
1912 super(exp.loc, null);
1913 assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
1914 this.sc = sc;
1915 this.arrayContent = exp;
1918 extern (D) this(Scope* sc, TypeTuple type) nothrow
1920 this.sc = sc;
1921 this.arrayContent = type;
1924 extern (D) this(Scope* sc, TupleDeclaration td) nothrow
1926 this.sc = sc;
1927 this.arrayContent = td;
1930 /// This override is used to solve `$`
1931 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
1933 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1934 if (ident != Id.dollar)
1935 return null;
1937 VarDeclaration* pvar;
1938 Expression ce;
1940 static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
1943 /* $ gives the number of type entries in the type tuple
1945 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1946 Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
1947 v._init = new ExpInitializer(Loc.initial, e);
1948 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1949 v.dsymbolSemantic(sc);
1950 return v;
1953 const DYNCAST kind = arrayContent.dyncast();
1954 if (kind == DYNCAST.dsymbol)
1956 TupleDeclaration td = cast(TupleDeclaration) arrayContent;
1957 /* $ gives the number of elements in the tuple
1959 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1960 Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
1961 v._init = new ExpInitializer(Loc.initial, e);
1962 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1963 v.dsymbolSemantic(sc);
1964 return v;
1966 if (kind == DYNCAST.type)
1968 return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
1970 Expression exp = cast(Expression) arrayContent;
1971 if (auto ie = exp.isIndexExp())
1973 /* array[index] where index is some function of $
1975 pvar = &ie.lengthVar;
1976 ce = ie.e1;
1978 else if (auto se = exp.isSliceExp())
1980 /* array[lwr .. upr] where lwr or upr is some function of $
1982 pvar = &se.lengthVar;
1983 ce = se.e1;
1985 else if (auto ae = exp.isArrayExp())
1987 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1988 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1990 pvar = &ae.lengthVar;
1991 ce = ae.e1;
1993 else
1995 /* Didn't find $, look in enclosing scope(s).
1997 return null;
1999 ce = ce.lastComma();
2000 /* If we are indexing into an array that is really a type
2001 * tuple, rewrite this as an index into a type tuple and
2002 * try again.
2004 if (auto te = ce.isTypeExp())
2006 if (auto ttp = te.type.isTypeTuple())
2007 return dollarFromTypeTuple(loc, ttp, sc);
2009 /* *pvar is lazily initialized, so if we refer to $
2010 * multiple times, it gets set only once.
2012 if (!*pvar) // if not already initialized
2014 /* Create variable v and set it to the value of $
2016 VarDeclaration v;
2017 Type t;
2018 if (auto tupexp = ce.isTupleExp())
2020 /* It is for an expression tuple, so the
2021 * length will be a const.
2023 Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
2024 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
2025 v.storage_class |= STC.temp | STC.static_ | STC.const_;
2027 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
2029 // Look for opDollar
2030 assert(exp.op == EXP.array || exp.op == EXP.slice);
2031 AggregateDeclaration ad = isAggregate(t);
2032 assert(ad);
2033 Dsymbol s = ad.search(loc, Id.opDollar);
2034 if (!s) // no dollar exists -- search in higher scope
2035 return null;
2036 s = s.toAlias();
2037 Expression e = null;
2038 // Check for multi-dimensional opDollar(dim) template.
2039 if (TemplateDeclaration td = s.isTemplateDeclaration())
2041 dinteger_t dim = 0;
2042 if (exp.op == EXP.array)
2044 dim = (cast(ArrayExp)exp).currentDimension;
2046 else if (exp.op == EXP.slice)
2048 dim = 0; // slices are currently always one-dimensional
2050 else
2052 assert(0);
2054 auto tiargs = new Objects();
2055 Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
2056 edim = edim.expressionSemantic(sc);
2057 tiargs.push(edim);
2058 e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
2060 else
2062 /* opDollar exists, but it's not a template.
2063 * This is acceptable ONLY for single-dimension indexing.
2064 * Note that it's impossible to have both template & function opDollar,
2065 * because both take no arguments.
2067 if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1)
2069 exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
2070 return null;
2072 Declaration d = s.isDeclaration();
2073 assert(d);
2074 e = new DotVarExp(loc, ce, d);
2076 e = e.expressionSemantic(sc);
2077 if (!e.type)
2078 exp.error("`%s` has no value", e.toChars());
2079 t = e.type.toBasetype();
2080 if (t && t.ty == Tfunction)
2081 e = new CallExp(e.loc, e);
2082 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
2083 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
2085 else
2087 /* For arrays, $ will either be a compile-time constant
2088 * (in which case its value in set during constant-folding),
2089 * or a variable (in which case an expression is created in
2090 * toir.c).
2092 auto e = new VoidInitializer(Loc.initial);
2093 e.type = Type.tsize_t;
2094 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
2095 v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
2097 *pvar = v;
2099 (*pvar).dsymbolSemantic(sc);
2100 return (*pvar);
2103 override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
2105 return this;
2108 override void accept(Visitor v)
2110 v.visit(this);
2114 /***********************************************************
2115 * Overload Sets
2117 extern (C++) final class OverloadSet : Dsymbol
2119 Dsymbols a; // array of Dsymbols
2121 extern (D) this(Identifier ident, OverloadSet os = null) nothrow
2123 super(ident);
2124 if (os)
2126 a.pushSlice(os.a[]);
2130 void push(Dsymbol s) nothrow
2132 a.push(s);
2135 override inout(OverloadSet) isOverloadSet() inout
2137 return this;
2140 override const(char)* kind() const
2142 return "overloadset";
2145 override void accept(Visitor v)
2147 v.visit(this);
2151 /***********************************************************
2152 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2153 * ForwardingScopeDeclaration to forward symbol insertions to another
2154 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2155 * details.
2157 extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
2159 /*************************
2160 * Symbol to forward insertions to.
2161 * Can be `null` before being lazily initialized.
2163 ScopeDsymbol forward;
2164 extern (D) this(ScopeDsymbol forward) nothrow
2166 super(null);
2167 this.forward = forward;
2170 override Dsymbol symtabInsert(Dsymbol s) nothrow
2172 assert(forward);
2173 if (auto d = s.isDeclaration())
2175 if (d.storage_class & STC.local)
2177 // Symbols with storage class STC.local are not
2178 // forwarded, but stored in the local symbol
2179 // table. (Those are the `static foreach` variables.)
2180 if (!symtab)
2182 symtab = new DsymbolTable();
2184 return super.symtabInsert(s); // insert locally
2187 if (!forward.symtab)
2189 forward.symtab = new DsymbolTable();
2191 // Non-STC.local symbols are forwarded to `forward`.
2192 return forward.symtabInsert(s);
2195 /************************
2196 * This override handles the following two cases:
2197 * static foreach (i, i; [0]) { ... }
2198 * and
2199 * static foreach (i; [0]) { enum i = 2; }
2201 override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
2203 assert(forward);
2204 // correctly diagnose clashing foreach loop variables.
2205 if (auto d = s.isDeclaration())
2207 if (d.storage_class & STC.local)
2209 if (!symtab)
2211 symtab = new DsymbolTable();
2213 return super.symtabLookup(s,id);
2216 // Declarations within `static foreach` do not clash with
2217 // `static foreach` loop variables.
2218 if (!forward.symtab)
2220 forward.symtab = new DsymbolTable();
2222 return forward.symtabLookup(s,id);
2225 override void importScope(Dsymbol s, Visibility visibility)
2227 forward.importScope(s, visibility);
2230 override const(char)* kind()const{ return "local scope"; }
2232 override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
2234 return this;
2240 * Class that holds an expression in a Dsymbol wrapper.
2241 * This is not an AST node, but a class used to pass
2242 * an expression as a function parameter of type Dsymbol.
2244 extern (C++) final class ExpressionDsymbol : Dsymbol
2246 Expression exp;
2247 this(Expression exp) nothrow
2249 super();
2250 this.exp = exp;
2253 override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
2255 return this;
2259 /**********************************************
2260 * Encapsulate assigning to an alias:
2261 * `identifier = type;`
2262 * `identifier = symbol;`
2263 * where `identifier` is an AliasDeclaration in scope.
2265 extern (C++) final class AliasAssign : Dsymbol
2267 Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
2268 Type type; /// replace previous RHS of AliasDeclaration with `type`
2269 Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
2270 /// only one of type and aliassym can be != null
2272 extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
2274 super(loc, null);
2275 this.ident = ident;
2276 this.type = type;
2277 this.aliassym = aliassym;
2280 override AliasAssign syntaxCopy(Dsymbol s)
2282 assert(!s);
2283 AliasAssign aa = new AliasAssign(loc, ident,
2284 type ? type.syntaxCopy() : null,
2285 aliassym ? aliassym.syntaxCopy(null) : null);
2286 return aa;
2289 override inout(AliasAssign) isAliasAssign() inout
2291 return this;
2294 override const(char)* kind() const
2296 return "alias assignment";
2299 override void accept(Visitor v)
2301 v.visit(this);
2305 /***********************************************************
2306 * Table of Dsymbol's
2308 extern (C++) final class DsymbolTable : RootObject
2310 AssocArray!(Identifier, Dsymbol) tab;
2312 nothrow:
2314 /***************************
2315 * Look up Identifier in symbol table
2316 * Params:
2317 * ident = identifer to look up
2318 * Returns:
2319 * Dsymbol if found, null if not
2321 Dsymbol lookup(const Identifier ident)
2323 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2324 return tab[ident];
2327 /**********
2328 * Replace existing symbol in symbol table with `s`.
2329 * If it's not there, add it.
2330 * Params:
2331 * s = replacement symbol with same identifier
2333 void update(Dsymbol s)
2335 *tab.getLvalue(s.ident) = s;
2338 /**************************
2339 * Insert Dsymbol in table.
2340 * Params:
2341 * s = symbol to add
2342 * Returns:
2343 * null if already in table, `s` if inserted
2345 Dsymbol insert(Dsymbol s)
2347 return insert(s.ident, s);
2350 /**************************
2351 * Insert Dsymbol in table.
2352 * Params:
2353 * ident = identifier to serve as index
2354 * s = symbol to add
2355 * Returns:
2356 * null if already in table, `s` if inserted
2358 Dsymbol insert(const Identifier ident, Dsymbol s)
2360 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2361 Dsymbol* ps = tab.getLvalue(ident);
2362 if (*ps)
2363 return null; // already in table
2364 *ps = s;
2365 return s;
2368 /*****************
2369 * Returns:
2370 * number of symbols in symbol table
2372 size_t length() const pure
2374 return tab.length;
2378 /**********************************************
2379 * ImportC tag symbols sit in a parallel symbol table,
2380 * so that this C code works:
2381 * ---
2382 * struct S { a; };
2383 * int S;
2384 * struct S s;
2385 * ---
2386 * But there are relatively few such tag symbols, so that would be
2387 * a waste of memory and complexity. An additional problem is we'd like the D side
2388 * to find the tag symbols with ordinary lookup, not lookup in both
2389 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2390 * The solution is to put the tag symbols that conflict into an associative
2391 * array, indexed by the address of the ordinary symbol that conflicts with it.
2392 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2393 * A side effect of our approach is that D code cannot access a tag symbol that is
2394 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2395 * has mentioned it when importing C headers. If someone wants to do it,
2396 * too bad so sad. Change the C code.
2397 * This function fixes up the symbol table when faced with adding a new symbol
2398 * `s` when there is an existing symbol `s2` with the same name.
2399 * C also allows forward and prototype declarations of tag symbols,
2400 * this function merges those.
2401 * Params:
2402 * sc = context
2403 * s = symbol to add to symbol table
2404 * s2 = existing declaration
2405 * sds = symbol table
2406 * Returns:
2407 * if s and s2 are successfully put in symbol table then return the merged symbol,
2408 * null if they conflict
2410 Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2412 enum log = false;
2413 if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
2414 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2415 auto sd = s.isScopeDsymbol(); // new declaration
2416 auto sd2 = s2.isScopeDsymbol(); // existing declaration
2418 if (!sd2)
2420 /* Look in tag table
2422 if (log) printf(" look in tag table\n");
2423 if (auto p = cast(void*)s2 in sc._module.tagSymTab)
2425 Dsymbol s2tag = *p;
2426 sd2 = s2tag.isScopeDsymbol();
2427 assert(sd2); // only tags allowed in tag symbol table
2431 if (sd && sd2) // `s` is a tag, `sd2` is the same tag
2433 if (log) printf(" tag is already defined\n");
2435 if (sd.kind() != sd2.kind()) // being enum/struct/union must match
2436 return null; // conflict
2438 /* Not a redeclaration if one is a forward declaration.
2439 * Move members to the first declared type, which is sd2.
2441 if (sd2.members)
2443 if (!sd.members)
2444 return sd2; // ignore the sd redeclaration
2446 else if (sd.members)
2448 sd2.members = sd.members; // transfer definition to sd2
2449 sd.members = null;
2450 return sd2;
2452 else
2453 return sd2; // ignore redeclaration
2455 else if (sd) // `s` is a tag, `s2` is not
2457 if (log) printf(" s is tag, s2 is not\n");
2458 /* add `s` as tag indexed by s2
2460 sc._module.tagSymTab[cast(void*)s2] = s;
2461 return s;
2463 else if (s2 is sd2) // `s2` is a tag, `s` is not
2465 if (log) printf(" s2 is tag, s is not\n");
2466 /* replace `s2` in symbol table with `s`,
2467 * then add `s2` as tag indexed by `s`
2469 sds.symtab.update(s);
2470 sc._module.tagSymTab[cast(void*)s] = s2;
2471 return s;
2473 // neither s2 nor s is a tag
2474 if (log) printf(" collision\n");
2475 return null;
2479 /**********************************************
2480 * ImportC allows redeclarations of C variables, functions and typedefs.
2481 * extern int x;
2482 * int x = 3;
2483 * and:
2484 * extern void f();
2485 * void f() { }
2486 * Attempt to merge them.
2487 * Params:
2488 * sc = context
2489 * s = symbol to add to symbol table
2490 * s2 = existing declaration
2491 * sds = symbol table
2492 * Returns:
2493 * if s and s2 are successfully put in symbol table then return the merged symbol,
2494 * null if they conflict
2496 Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2498 enum log = false;
2499 if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
2500 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2502 static Dsymbol collision()
2504 if (log) printf(" collision\n");
2505 return null;
2508 auto vd = s.isVarDeclaration(); // new declaration
2509 auto vd2 = s2.isVarDeclaration(); // existing declaration
2510 if (vd && vd2)
2512 /* if one is `static` and the other isn't, the result is undefined
2513 * behavior, C11 6.2.2.7
2515 if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
2516 return collision();
2518 const i1 = vd._init && ! vd._init.isVoidInitializer();
2519 const i2 = vd2._init && !vd2._init.isVoidInitializer();
2521 if (i1 && i2)
2522 return collision(); // can't both have initializers
2524 if (i1) // vd is the definition
2526 sds.symtab.update(vd); // replace vd2 with the definition
2527 return vd;
2530 /* BUG: the types should match, which needs semantic() to be run on it
2531 * extern int x;
2532 * int x; // match
2533 * typedef int INT;
2534 * INT x; // match
2535 * long x; // collision
2536 * We incorrectly ignore these collisions
2538 return vd2;
2541 auto fd = s.isFuncDeclaration(); // new declaration
2542 auto fd2 = s2.isFuncDeclaration(); // existing declaration
2543 if (fd && fd2)
2545 /* if one is `static` and the other isn't, the result is undefined
2546 * behavior, C11 6.2.2.7
2547 * However, match what gcc allows:
2548 * static int sun1(); int sun1() { return 0; }
2549 * and:
2550 * static int sun2() { return 0; } int sun2();
2551 * Both produce a static function.
2553 * Both of these should fail:
2554 * int sun3(); static int sun3() { return 0; }
2555 * and:
2556 * int sun4() { return 0; } static int sun4();
2558 // if adding `static`
2559 if ( fd.storage_class & STC.static_ &&
2560 !(fd2.storage_class & STC.static_))
2562 return collision();
2565 if (fd.fbody && fd2.fbody)
2566 return collision(); // can't both have bodies
2568 if (fd.fbody) // fd is the definition
2570 if (log) printf(" replace existing with new\n");
2571 sds.symtab.update(fd); // replace fd2 in symbol table with fd
2572 fd.overnext = fd2;
2574 /* If fd2 is covering a tag symbol, then fd has to cover the same one
2576 auto ps = cast(void*)fd2 in sc._module.tagSymTab;
2577 if (ps)
2578 sc._module.tagSymTab[cast(void*)fd] = *ps;
2580 return fd;
2583 /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2584 * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
2586 fd2.overloadInsert(fd);
2588 return fd2;
2591 auto td = s.isAliasDeclaration(); // new declaration
2592 auto td2 = s2.isAliasDeclaration(); // existing declaration
2593 if (td && td2)
2595 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2596 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2598 return td2;
2601 return collision();