1 /**
2  * The base class for a D symbol, which can be a module, variable, function, enum, etc.
3  *
4  * Copyright:   Copyright (C) 1999-2023 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
10  */
11 
12 module dmd.dsymbol;
13 
14 import core.stdc.stdarg;
15 import core.stdc.stdio;
16 import core.stdc.string;
17 import core.stdc.stdlib;
18 
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.location;
46 import dmd.mtype;
47 import dmd.nspace;
48 import dmd.opover;
49 import dmd.root.aav;
50 import dmd.root.rmem;
51 import dmd.root.rootobject;
52 import dmd.root.speller;
53 import dmd.root.string;
54 import dmd.statement;
55 import dmd.staticassert;
56 import dmd.tokens;
57 import dmd.visitor;
58 
59 /***************************************
60  * Calls dg(Dsymbol *sym) for each Dsymbol.
61  * If dg returns !=0, stops and returns that value else returns 0.
62  * Params:
63  *    symbols = Dsymbols
64  *    dg = delegate to call for each Dsymbol
65  * Returns:
66  *    last value returned by dg()
67  *
68  * See_Also: $(REF each, dmd, root, array)
69  */
70 int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
71 {
72     assert(dg);
73     if (symbols)
74     {
75         /* Do not use foreach, as the size of the array may expand during iteration
76          */
77         for (size_t i = 0; i < symbols.length; ++i)
78         {
79             Dsymbol s = (*symbols)[i];
80             const result = dg(s);
81             if (result)
82                 return result;
83         }
84     }
85     return 0;
86 }
87 
88 /***************************************
89  * Calls dg(Dsymbol *sym) for each Dsymbol.
90  * Params:
91  *    symbols = Dsymbols
92  *    dg = delegate to call for each Dsymbol
93  *
94  * See_Also: $(REF each, dmd, root, array)
95  */
96 void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
97 {
98     assert(dg);
99     if (symbols)
100     {
101         /* Do not use foreach, as the size of the array may expand during iteration
102          */
103         for (size_t i = 0; i < symbols.length; ++i)
104         {
105             Dsymbol s = (*symbols)[i];
106             dg(s);
107         }
108     }
109 }
110 
111 
112 struct Ungag
113 {
114     uint oldgag;
115 
116     extern (D) this(uint old) nothrow
117     {
118         this.oldgag = old;
119     }
120 
121     extern (C++) ~this() nothrow
122     {
123         global.gag = oldgag;
124     }
125 }
126 
127 struct Visibility
128 {
129     ///
130     enum Kind : ubyte
131     {
132         undefined,
133         none,           // no access
134         private_,
135         package_,
136         protected_,
137         public_,
138         export_,
139     }
140 
141     Kind kind;
142     Package pkg;
143 
144     extern (D):
145 
146     this(Visibility.Kind kind) pure nothrow @nogc @safe
147     {
148         this.kind = kind;
149     }
150 
151     /**
152      * Checks if `this` is less or more visible than `other`
153      *
154      * Params:
155      *   other = Visibility to compare `this` to.
156      *
157      * Returns:
158      *   A value `< 0` if `this` is less visible than `other`,
159      *   a value `> 0` if `this` is more visible than `other`,
160      *   and `0` if they are at the same level.
161      *   Note that `package` visibility with different packages
162      *   will also return `0`.
163      */
164     int opCmp(const Visibility other) const pure nothrow @nogc @safe
165     {
166         return this.kind - other.kind;
167     }
168 
169     ///
170     unittest
171     {
172         assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_));
173         assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_));
174         assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_));
175     }
176 
177     /**
178      * Checks if `this` is absolutely identical visibility attribute to `other`
179      */
180     bool opEquals(ref const Visibility other) const
181     {
182         if (this.kind == other.kind)
183         {
184             if (this.kind == Visibility.Kind.package_)
185                 return this.pkg == other.pkg;
186             return true;
187         }
188         return false;
189     }
190 }
191 
192 enum PASS : ubyte
193 {
194     initial,        // initial state
195     semantic,       // semantic() started
196     semanticdone,   // semantic() done
197     semantic2,      // semantic2() started
198     semantic2done,  // semantic2() done
199     semantic3,      // semantic3() started
200     semantic3done,  // semantic3() done
201     inline,         // inline started
202     inlinedone,     // inline done
203     obj,            // toObjFile() run
204 }
205 
206 // Search options
207 enum : int
208 {
209     IgnoreNone              = 0x00, // default
210     IgnorePrivateImports    = 0x01, // don't search private imports
211     IgnoreErrors            = 0x02, // don't give error messages
212     IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
213     SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
214     SearchImportsOnly       = 0x10, // only look in imports
215     SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
216                                     // meaning don't search imports in that scope,
217                                     // because qualified module searches search
218                                     // their imports
219     IgnoreSymbolVisibility  = 0x80, // also find private and package protected symbols
220     TagNameSpace            = 0x100, // search ImportC tag symbol table
221 }
222 
223 /***********************************************************
224  * Struct/Class/Union field state.
225  * Used for transitory information when setting field offsets, such
226  * as bit fields.
227  */
228 struct FieldState
229 {
230     uint offset;        /// byte offset for next field
231 
232     uint fieldOffset;   /// byte offset for the start of the bit field
233     uint fieldSize;     /// byte size of field
234     uint fieldAlign;    /// byte alignment of field
235     uint bitOffset;     /// bit offset for field
236 
237     bool inFlight;      /// bit field is in flight
238 }
239 
240 // 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos),
241 // so save memory by grouping them into a separate struct
242 private struct DsymbolAttributes
243 {
244     /// C++ namespace this symbol belongs to
245     CPPNamespaceDeclaration cppnamespace;
246     /// customized deprecation message
247     DeprecatedDeclaration depdecl_;
248     /// user defined attributes
249     UserAttributeDeclaration userAttribDecl;
250 }
251 
252 /***********************************************************
253  */
254 extern (C++) class Dsymbol : ASTNode
255 {
256     Identifier ident;
257     Dsymbol parent;
258     Symbol* csym;           // symbol for code generator
259     const Loc loc;          // where defined
260     Scope* _scope;          // !=null means context to use for semantic()
261     const(char)* prettystring;  // cached value of toPrettyChars()
262     private DsymbolAttributes* atts; /// attached attribute declarations
263     bool errors;            // this symbol failed to pass semantic()
264     PASS semanticRun = PASS.initial;
265     ushort localNum;        /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
266 
267     final extern (D) this() nothrow
268     {
269         //printf("Dsymbol::Dsymbol(%p)\n", this);
270         loc = Loc(null, 0, 0);
271     }
272 
273     final extern (D) this(Identifier ident) nothrow
274     {
275         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
276         this.loc = Loc(null, 0, 0);
277         this.ident = ident;
278     }
279 
280     final extern (D) this(const ref Loc loc, Identifier ident) nothrow
281     {
282         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
283         this.loc = loc;
284         this.ident = ident;
285     }
286 
287     static Dsymbol create(Identifier ident) nothrow
288     {
289         return new Dsymbol(ident);
290     }
291 
292     override const(char)* toChars() const
293     {
294         return ident ? ident.toChars() : "__anonymous";
295     }
296 
297     // Getters / setters for fields stored in `DsymbolAttributes`
298     final nothrow pure @safe
299     {
300         private ref DsymbolAttributes getAtts()
301         {
302             if (!atts)
303                 atts = new DsymbolAttributes();
304             return *atts;
305         }
306 
307         inout(DeprecatedDeclaration) depdecl() inout { return atts ? atts.depdecl_ : null; }
308         inout(CPPNamespaceDeclaration) cppnamespace() inout { return atts ? atts.cppnamespace : null; }
309         inout(UserAttributeDeclaration) userAttribDecl() inout { return atts ? atts.userAttribDecl : null; }
310 
311         DeprecatedDeclaration depdecl(DeprecatedDeclaration dd)
312         {
313             if (!dd && !atts)
314                 return null;
315             return getAtts().depdecl_ = dd;
316         }
317 
318         CPPNamespaceDeclaration cppnamespace(CPPNamespaceDeclaration ns)
319         {
320             if (!ns && !atts)
321                 return null;
322             return getAtts().cppnamespace = ns;
323         }
324 
325         UserAttributeDeclaration userAttribDecl(UserAttributeDeclaration uad)
326         {
327             if (!uad && !atts)
328                 return null;
329             return getAtts().userAttribDecl = uad;
330         }
331     }
332 
333     // helper to print fully qualified (template) arguments
334     const(char)* toPrettyCharsHelper()
335     {
336         return toChars();
337     }
338 
339     final const(Loc) getLoc()
340     {
341         if (!loc.isValid()) // avoid bug 5861.
342             if (const m = getModule())
343                 return Loc(m.srcfile.toChars(), 0, 0);
344         return loc;
345     }
346 
347     final const(char)* locToChars()
348     {
349         return getLoc().toChars();
350     }
351 
352     override bool equals(const RootObject o) const
353     {
354         if (this == o)
355             return true;
356         if (o.dyncast() != DYNCAST.dsymbol)
357             return false;
358         auto s = cast(Dsymbol)o;
359         // Overload sets don't have an ident
360         // Function-local declarations may have identical names
361         // if they are declared in different scopes
362         if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum)
363             return true;
364         return false;
365     }
366 
367     final bool isAnonymous() const
368     {
369         return ident is null || ident.isAnonymous;
370     }
371 
372     extern(D) private const(char)[] prettyFormatHelper()
373     {
374         const cstr = toPrettyChars();
375         return '`' ~ cstr.toDString() ~ "`\0";
376     }
377 
378     static if (__VERSION__ < 2092)
379     {
380         final void error(const ref Loc loc, const(char)* format, ...)
381         {
382             va_list ap;
383             va_start(ap, format);
384             .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
385             va_end(ap);
386         }
387 
388         final void error(const(char)* format, ...)
389         {
390             va_list ap;
391             va_start(ap, format);
392             const loc = getLoc();
393             .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
394             va_end(ap);
395         }
396 
397         final void deprecation(const ref Loc loc, const(char)* format, ...)
398         {
399             va_list ap;
400             va_start(ap, format);
401             .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
402             va_end(ap);
403         }
404 
405         final void deprecation(const(char)* format, ...)
406         {
407             va_list ap;
408             va_start(ap, format);
409             const loc = getLoc();
410             .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
411             va_end(ap);
412         }
413     }
414     else
415     {
416         pragma(printf) final void error(const ref Loc loc, const(char)* format, ...)
417         {
418             va_list ap;
419             va_start(ap, format);
420             .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
421             va_end(ap);
422         }
423 
424         pragma(printf) final void error(const(char)* format, ...)
425         {
426             va_list ap;
427             va_start(ap, format);
428             const loc = getLoc();
429             .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
430             va_end(ap);
431         }
432 
433         pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...)
434         {
435             va_list ap;
436             va_start(ap, format);
437             .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
438             va_end(ap);
439         }
440 
441         pragma(printf) final void deprecation(const(char)* format, ...)
442         {
443             va_list ap;
444             va_start(ap, format);
445             const loc = getLoc();
446             .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
447             va_end(ap);
448         }
449     }
450 
451     final bool checkDeprecated(const ref Loc loc, Scope* sc)
452     {
453         if (global.params.useDeprecated == DiagnosticReporting.off)
454             return false;
455         if (!this.isDeprecated())
456             return false;
457         // Don't complain if we're inside a deprecated symbol's scope
458         if (sc.isDeprecated())
459             return false;
460         // Don't complain if we're inside a template constraint
461         // https://issues.dlang.org/show_bug.cgi?id=21831
462         if (sc.flags & SCOPE.constraint)
463             return false;
464 
465         const(char)* message = null;
466         for (Dsymbol p = this; p; p = p.parent)
467         {
468             message = p.depdecl ? p.depdecl.getMessage() : null;
469             if (message)
470                 break;
471         }
472         if (message)
473             deprecation(loc, "is deprecated - %s", message);
474         else
475             deprecation(loc, "is deprecated");
476 
477         if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
478             ti.printInstantiationTrace(Classification.deprecation);
479         else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
480             ti.printInstantiationTrace(Classification.deprecation);
481 
482         return true;
483     }
484 
485     /**********************************
486      * Determine which Module a Dsymbol is in.
487      */
488     final Module getModule()
489     {
490         //printf("Dsymbol::getModule()\n");
491         if (TemplateInstance ti = isInstantiated())
492             return ti.tempdecl.getModule();
493         Dsymbol s = this;
494         while (s)
495         {
496             //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
497             Module m = s.isModule();
498             if (m)
499                 return m;
500             s = s.parent;
501         }
502         return null;
503     }
504 
505     /**************************************
506      * Does this Dsymbol come from a C file?
507      * Returns:
508      *  true if it does
509      */
510      final bool isCsymbol()
511      {
512         if (Module m = getModule())
513             return m.filetype == FileType.c;
514         return false;
515     }
516 
517     /**********************************
518      * Determine which Module a Dsymbol is in, as far as access rights go.
519      */
520     final Module getAccessModule()
521     {
522         //printf("Dsymbol::getAccessModule()\n");
523         if (TemplateInstance ti = isInstantiated())
524             return ti.tempdecl.getAccessModule();
525         Dsymbol s = this;
526         while (s)
527         {
528             //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
529             Module m = s.isModule();
530             if (m)
531                 return m;
532             TemplateInstance ti = s.isTemplateInstance();
533             if (ti && ti.enclosing)
534             {
535                 /* Because of local template instantiation, the parent isn't where the access
536                  * rights come from - it's the template declaration
537                  */
538                 s = ti.tempdecl;
539             }
540             else
541                 s = s.parent;
542         }
543         return null;
544     }
545 
546     /**
547      * `pastMixin` returns the enclosing symbol if this is a template mixin.
548      *
549      * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
550      * are mangleOnly.
551      *
552      * See also `parent`, `toParent` and `toParent2`.
553      */
554     final inout(Dsymbol) pastMixin() inout
555     {
556         //printf("Dsymbol::pastMixin() %s\n", toChars());
557         if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
558             return this;
559         if (!parent)
560             return null;
561         return parent.pastMixin();
562     }
563 
564     /**********************************
565      * `parent` field returns a lexically enclosing scope symbol this is a member of.
566      *
567      * `toParent()` returns a logically enclosing scope symbol this is a member of.
568      * It skips over TemplateMixin's.
569      *
570      * `toParent2()` returns an enclosing scope symbol this is living at runtime.
571      * It skips over both TemplateInstance's and TemplateMixin's.
572      * It's used when looking for the 'this' pointer of the enclosing function/class.
573      *
574      * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
575      * instead of the instantiation scope.
576      *
577      * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
578      * if a template declaration is non-local i.e. global or static.
579      *
580      * Examples:
581      * ---
582      *  module mod;
583      *  template Foo(alias a) { mixin Bar!(); }
584      *  mixin template Bar() {
585      *    public {  // VisibilityDeclaration
586      *      void baz() { a = 2; }
587      *    }
588      *  }
589      *  void test() {
590      *    int v = 1;
591      *    alias foo = Foo!(v);
592      *    foo.baz();
593      *    assert(v == 2);
594      *  }
595      *
596      *  // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
597      *  // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
598      *  // s.toParent() == TemplateInstance('mod.test.Foo!()')
599      *  // s.toParent2() == FuncDeclaration('mod.test')
600      *  // s.toParentDecl() == Module('mod')
601      *  // s.toParentLocal() == FuncDeclaration('mod.test')
602      * ---
603      */
604     final inout(Dsymbol) toParent() inout
605     {
606         return parent ? parent.pastMixin() : null;
607     }
608 
609     /// ditto
610     final inout(Dsymbol) toParent2() inout
611     {
612         if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
613             return parent;
614         return parent.toParent2;
615     }
616 
617     /// ditto
618     final inout(Dsymbol) toParentDecl() inout
619     {
620         return toParentDeclImpl(false);
621     }
622 
623     /// ditto
624     final inout(Dsymbol) toParentLocal() inout
625     {
626         return toParentDeclImpl(true);
627     }
628 
629     private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
630     {
631         auto p = toParent();
632         if (!p || !p.isTemplateInstance())
633             return p;
634         auto ti = p.isTemplateInstance();
635         if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
636             return ti.tempdecl.toParentDeclImpl(localOnly);
637         return parent.toParentDeclImpl(localOnly);
638     }
639 
640     /**
641      * Returns the declaration scope scope of `this` unless any of the symbols
642      * `p1` or `p2` resides in its enclosing instantiation scope then the
643      * latter is returned.
644      */
645     final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
646     {
647         return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
648     }
649 
650     final inout(TemplateInstance) isInstantiated() inout
651     {
652         if (!parent)
653             return null;
654         auto ti = parent.isTemplateInstance();
655         if (ti && !ti.isTemplateMixin())
656             return ti;
657         return parent.isInstantiated();
658     }
659 
660     /***
661      * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
662      * instantiation scope of `this`.
663      */
664     final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
665     {
666         static bool has2This(Dsymbol s)
667         {
668             if (auto f = s.isFuncDeclaration())
669                 return f.hasDualContext();
670             if (auto ad = s.isAggregateDeclaration())
671                 return ad.vthis2 !is null;
672             return false;
673         }
674 
675         if (has2This(this))
676         {
677             assert(p1);
678             auto outer = toParent();
679             while (outer)
680             {
681                 auto ti = outer.isTemplateInstance();
682                 if (!ti)
683                     break;
684                 foreach (oarg; *ti.tiargs)
685                 {
686                     auto sa = getDsymbol(oarg);
687                     if (!sa)
688                         continue;
689                     sa = sa.toAlias().toParent2();
690                     if (!sa)
691                         continue;
692                     if (sa == p1)
693                         return true;
694                     else if (p2 && sa == p2)
695                         return true;
696                 }
697                 outer = ti.tempdecl.toParent();
698             }
699             return false;
700         }
701         return false;
702     }
703 
704     // Check if this function is a member of a template which has only been
705     // instantiated speculatively, eg from inside is(typeof()).
706     // Return the speculative template instance it is part of,
707     // or NULL if not speculative.
708     final inout(TemplateInstance) isSpeculative() inout
709     {
710         if (!parent)
711             return null;
712         auto ti = parent.isTemplateInstance();
713         if (ti && ti.gagged)
714             return ti;
715         if (!parent.toParent())
716             return null;
717         return parent.isSpeculative();
718     }
719 
720     final Ungag ungagSpeculative() const
721     {
722         uint oldgag = global.gag;
723         if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
724             global.gag = 0;
725         return Ungag(oldgag);
726     }
727 
728     // kludge for template.isSymbol()
729     override final DYNCAST dyncast() const
730     {
731         return DYNCAST.dsymbol;
732     }
733 
734     /*************************************
735      * Do syntax copy of an array of Dsymbol's.
736      */
737     extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
738     {
739         Dsymbols* b = null;
740         if (a)
741         {
742             b = a.copy();
743             for (size_t i = 0; i < b.length; i++)
744             {
745                 (*b)[i] = (*b)[i].syntaxCopy(null);
746             }
747         }
748         return b;
749     }
750 
751     Identifier getIdent()
752     {
753         return ident;
754     }
755 
756     const(char)* toPrettyChars(bool QualifyTypes = false)
757     {
758         if (prettystring && !QualifyTypes)
759             return prettystring;
760 
761         //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
762         if (!parent)
763         {
764             auto s = toChars();
765             if (!QualifyTypes)
766                 prettystring = s;
767             return s;
768         }
769 
770         // Computer number of components
771         size_t complength = 0;
772         for (Dsymbol p = this; p; p = p.parent)
773             ++complength;
774 
775         // Allocate temporary array comp[]
776         alias T = const(char)[];
777         auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
778         auto comp = compptr[0 .. complength];
779 
780         // Fill in comp[] and compute length of final result
781         size_t length = 0;
782         int i;
783         for (Dsymbol p = this; p; p = p.parent)
784         {
785             const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
786             const len = strlen(s);
787             comp[i] = s[0 .. len];
788             ++i;
789             length += len + 1;
790         }
791 
792         auto s = cast(char*)mem.xmalloc_noscan(length);
793         auto q = s + length - 1;
794         *q = 0;
795         foreach (j; 0 .. complength)
796         {
797             const t = comp[j].ptr;
798             const len = comp[j].length;
799             q -= len;
800             memcpy(q, t, len);
801             if (q == s)
802                 break;
803             *--q = '.';
804         }
805         free(comp.ptr);
806         if (!QualifyTypes)
807             prettystring = s;
808         return s;
809     }
810 
811     const(char)* kind() const pure nothrow @nogc @safe
812     {
813         return "symbol";
814     }
815 
816     /*********************************
817      * If this symbol is really an alias for another,
818      * return that other.
819      * If needed, semantic() is invoked due to resolve forward reference.
820      */
821     Dsymbol toAlias()
822     {
823         return this;
824     }
825 
826     /*********************************
827      * Resolve recursive tuple expansion in eponymous template.
828      */
829     Dsymbol toAlias2()
830     {
831         return toAlias();
832     }
833 
834     void addMember(Scope* sc, ScopeDsymbol sds)
835     {
836         //printf("Dsymbol::addMember('%s')\n", toChars());
837         //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
838         //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
839         parent = sds;
840         if (isAnonymous()) // no name, so can't add it to symbol table
841             return;
842 
843         if (!sds.symtabInsert(this)) // if name is already defined
844         {
845             if (isAliasDeclaration() && !_scope)
846                 setScope(sc);
847             Dsymbol s2 = sds.symtabLookup(this,ident);
848             /* https://issues.dlang.org/show_bug.cgi?id=17434
849              *
850              * If we are trying to add an import to the symbol table
851              * that has already been introduced, then keep the one with
852              * larger visibility. This is fine for imports because if
853              * we have multiple imports of the same file, if a single one
854              * is public then the symbol is reachable.
855              */
856             if (auto i1 = isImport())
857             {
858                 if (auto i2 = s2.isImport())
859                 {
860                     if (sc.explicitVisibility && sc.visibility > i2.visibility)
861                         sds.symtab.update(this);
862                 }
863             }
864 
865             // If using C tag/prototype/forward declaration rules
866             if (sc.flags & SCOPE.Cfile && !this.isImport())
867             {
868                 if (handleTagSymbols(*sc, this, s2, sds))
869                     return;
870                 if (handleSymbolRedeclarations(*sc, this, s2, sds))
871                     return;
872 
873                 sds.multiplyDefined(Loc.initial, this, s2);  // ImportC doesn't allow overloading
874                 errors = true;
875                 return;
876             }
877 
878             if (!s2.overloadInsert(this))
879             {
880                 sds.multiplyDefined(Loc.initial, this, s2);
881                 errors = true;
882             }
883         }
884         if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
885         {
886             if (ident == Id.__sizeof ||
887                 !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
888             {
889                 error("`.%s` property cannot be redefined", ident.toChars());
890                 errors = true;
891             }
892         }
893     }
894 
895     /*************************************
896      * Set scope for future semantic analysis so we can
897      * deal better with forward references.
898      */
899     void setScope(Scope* sc)
900     {
901         //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
902         if (!sc.nofree)
903             sc.setNoFree(); // may need it even after semantic() finishes
904         _scope = sc;
905         if (sc.depdecl)
906             depdecl = sc.depdecl;
907         if (!userAttribDecl)
908             userAttribDecl = sc.userAttribDecl;
909     }
910 
911     void importAll(Scope* sc)
912     {
913     }
914 
915     /*********************************************
916      * Search for ident as member of s.
917      * Params:
918      *  loc = location to print for error messages
919      *  ident = identifier to search for
920      *  flags = IgnoreXXXX
921      * Returns:
922      *  null if not found
923      */
924     Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
925     {
926         //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
927         return null;
928     }
929 
930     extern (D) final Dsymbol search_correct(Identifier ident)
931     {
932         /***************************************************
933          * Search for symbol with correct spelling.
934          */
935         extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
936         {
937             /* If not in the lexer's string table, it certainly isn't in the symbol table.
938              * Doing this first is a lot faster.
939              */
940             if (!seed.length)
941                 return null;
942             Identifier id = Identifier.lookup(seed);
943             if (!id)
944                 return null;
945             cost = 0;   // all the same cost
946             Dsymbol s = this;
947             Module.clearCache();
948             return s.search(Loc.initial, id, IgnoreErrors);
949         }
950 
951         if (global.gag)
952             return null; // don't do it for speculative compiles; too time consuming
953         // search for exact name first
954         if (auto s = search(Loc.initial, ident, IgnoreErrors))
955             return s;
956         return speller!symbol_search_fp(ident.toString());
957     }
958 
959     /***************************************
960      * Search for identifier id as a member of `this`.
961      * `id` may be a template instance.
962      *
963      * Params:
964      *  loc = location to print the error messages
965      *  sc = the scope where the symbol is located
966      *  id = the id of the symbol
967      *  flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
968      *
969      * Returns:
970      *      symbol found, NULL if not
971      */
972     extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
973     {
974         //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
975         Dsymbol s = toAlias();
976         Dsymbol sm;
977         if (Declaration d = s.isDeclaration())
978         {
979             if (d.inuse)
980             {
981                 .error(loc, "circular reference to `%s`", d.toPrettyChars());
982                 return null;
983             }
984         }
985         switch (id.dyncast())
986         {
987         case DYNCAST.identifier:
988             sm = s.search(loc, cast(Identifier)id, flags);
989             break;
990         case DYNCAST.dsymbol:
991             {
992                 // It's a template instance
993                 //printf("\ttemplate instance id\n");
994                 Dsymbol st = cast(Dsymbol)id;
995                 TemplateInstance ti = st.isTemplateInstance();
996                 sm = s.search(loc, ti.name);
997                 if (!sm)
998                     return null;
999                 sm = sm.toAlias();
1000                 TemplateDeclaration td = sm.isTemplateDeclaration();
1001                 if (!td)
1002                     return null; // error but handled later
1003                 ti.tempdecl = td;
1004                 if (!ti.semanticRun)
1005                     ti.dsymbolSemantic(sc);
1006                 sm = ti.toAlias();
1007                 break;
1008             }
1009         case DYNCAST.type:
1010         case DYNCAST.expression:
1011         default:
1012             assert(0);
1013         }
1014         return sm;
1015     }
1016 
1017     bool overloadInsert(Dsymbol s)
1018     {
1019         //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
1020         return false;
1021     }
1022 
1023     /*********************************
1024      * Returns:
1025      *  SIZE_INVALID when the size cannot be determined
1026      */
1027     uinteger_t size(const ref Loc loc)
1028     {
1029         error("symbol `%s` has no size", toChars());
1030         return SIZE_INVALID;
1031     }
1032 
1033     bool isforwardRef()
1034     {
1035         return false;
1036     }
1037 
1038     // is a 'this' required to access the member
1039     inout(AggregateDeclaration) isThis() inout
1040     {
1041         return null;
1042     }
1043 
1044     // is Dsymbol exported?
1045     bool isExport() const
1046     {
1047         return false;
1048     }
1049 
1050     // is Dsymbol imported?
1051     bool isImportedSymbol() const
1052     {
1053         return false;
1054     }
1055 
1056     // is Dsymbol deprecated?
1057     bool isDeprecated() @safe @nogc pure nothrow const
1058     {
1059         return false;
1060     }
1061 
1062     bool isOverloadable() const
1063     {
1064         return false;
1065     }
1066 
1067     // is this a LabelDsymbol()?
1068     LabelDsymbol isLabel()
1069     {
1070         return null;
1071     }
1072 
1073     /// Returns an AggregateDeclaration when toParent() is that.
1074     final inout(AggregateDeclaration) isMember() inout
1075     {
1076         //printf("Dsymbol::isMember() %s\n", toChars());
1077         auto p = toParent();
1078         //printf("parent is %s %s\n", p.kind(), p.toChars());
1079         return p ? p.isAggregateDeclaration() : null;
1080     }
1081 
1082     /// Returns an AggregateDeclaration when toParent2() is that.
1083     final inout(AggregateDeclaration) isMember2() inout
1084     {
1085         //printf("Dsymbol::isMember2() '%s'\n", toChars());
1086         auto p = toParent2();
1087         //printf("parent is %s %s\n", p.kind(), p.toChars());
1088         return p ? p.isAggregateDeclaration() : null;
1089     }
1090 
1091     /// Returns an AggregateDeclaration when toParentDecl() is that.
1092     final inout(AggregateDeclaration) isMemberDecl() inout
1093     {
1094         //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1095         auto p = toParentDecl();
1096         //printf("parent is %s %s\n", p.kind(), p.toChars());
1097         return p ? p.isAggregateDeclaration() : null;
1098     }
1099 
1100     /// Returns an AggregateDeclaration when toParentLocal() is that.
1101     final inout(AggregateDeclaration) isMemberLocal() inout
1102     {
1103         //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1104         auto p = toParentLocal();
1105         //printf("parent is %s %s\n", p.kind(), p.toChars());
1106         return p ? p.isAggregateDeclaration() : null;
1107     }
1108 
1109     // is this a member of a ClassDeclaration?
1110     final ClassDeclaration isClassMember()
1111     {
1112         auto ad = isMember();
1113         return ad ? ad.isClassDeclaration() : null;
1114     }
1115 
1116     // is this a type?
1117     Type getType()
1118     {
1119         return null;
1120     }
1121 
1122     // need a 'this' pointer?
1123     bool needThis()
1124     {
1125         return false;
1126     }
1127 
1128     /*************************************
1129      */
1130     Visibility visible() pure nothrow @nogc @safe
1131     {
1132         return Visibility(Visibility.Kind.public_);
1133     }
1134 
1135     /**************************************
1136      * Copy the syntax.
1137      * Used for template instantiations.
1138      * If s is NULL, allocate the new object, otherwise fill it in.
1139      */
1140     Dsymbol syntaxCopy(Dsymbol s)
1141     {
1142         printf("%s %s\n", kind(), toChars());
1143         assert(0);
1144     }
1145 
1146     /**************************************
1147      * Determine if this symbol is only one.
1148      * Returns:
1149      *      false, *ps = NULL: There are 2 or more symbols
1150      *      true,  *ps = NULL: There are zero symbols
1151      *      true,  *ps = symbol: The one and only one symbol
1152      */
1153     bool oneMember(Dsymbol* ps, Identifier ident)
1154     {
1155         //printf("Dsymbol::oneMember()\n");
1156         *ps = this;
1157         return true;
1158     }
1159 
1160     /*****************************************
1161      * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1162      */
1163     extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
1164     {
1165         //printf("Dsymbol::oneMembers() %d\n", members ? members.length : 0);
1166         Dsymbol s = null;
1167         if (!members)
1168         {
1169             *ps = null;
1170             return true;
1171         }
1172 
1173         for (size_t i = 0; i < members.length; i++)
1174         {
1175             Dsymbol sx = (*members)[i];
1176             bool x = sx.oneMember(ps, ident);
1177             //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1178             if (!x)
1179             {
1180                 //printf("\tfalse 1\n");
1181                 assert(*ps is null);
1182                 return false;
1183             }
1184             if (*ps)
1185             {
1186                 assert(ident);
1187                 if (!(*ps).ident || !(*ps).ident.equals(ident))
1188                     continue;
1189                 if (!s)
1190                     s = *ps;
1191                 else if (s.isOverloadable() && (*ps).isOverloadable())
1192                 {
1193                     // keep head of overload set
1194                     FuncDeclaration f1 = s.isFuncDeclaration();
1195                     FuncDeclaration f2 = (*ps).isFuncDeclaration();
1196                     if (f1 && f2)
1197                     {
1198                         assert(!f1.isFuncAliasDeclaration());
1199                         assert(!f2.isFuncAliasDeclaration());
1200                         for (; f1 != f2; f1 = f1.overnext0)
1201                         {
1202                             if (f1.overnext0 is null)
1203                             {
1204                                 f1.overnext0 = f2;
1205                                 break;
1206                             }
1207                         }
1208                     }
1209                 }
1210                 else // more than one symbol
1211                 {
1212                     *ps = null;
1213                     //printf("\tfalse 2\n");
1214                     return false;
1215                 }
1216             }
1217         }
1218         *ps = s; // s is the one symbol, null if none
1219         //printf("\ttrue\n");
1220         return true;
1221     }
1222 
1223     void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
1224     {
1225     }
1226 
1227     /*****************************************
1228      * Is Dsymbol a variable that contains pointers?
1229      */
1230     bool hasPointers()
1231     {
1232         //printf("Dsymbol::hasPointers() %s\n", toChars());
1233         return false;
1234     }
1235 
1236     bool hasStaticCtorOrDtor()
1237     {
1238         //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1239         return false;
1240     }
1241 
1242     void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1243     {
1244     }
1245 
1246     void checkCtorConstInit()
1247     {
1248     }
1249 
1250     /****************************************
1251      * Add documentation comment to Dsymbol.
1252      * Ignore NULL comments.
1253      */
1254     void addComment(const(char)* comment)
1255     {
1256         if (!comment || !*comment)
1257             return;
1258 
1259         //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
1260         void* h = cast(void*)this;      // just the pointer is the key
1261         auto p = h in commentHashTable;
1262         if (!p)
1263         {
1264             commentHashTable[h] = comment;
1265             return;
1266         }
1267         if (strcmp(*p, comment) != 0)
1268         {
1269             // Concatenate the two
1270             *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
1271         }
1272     }
1273 
1274     /// get documentation comment for this Dsymbol
1275     final const(char)* comment()
1276     {
1277         //printf("getcomment: %p '%s'\n", this, this.toChars());
1278         if (auto p = cast(void*)this in commentHashTable)
1279         {
1280             //printf("comment: '%s'\n", *p);
1281             return *p;
1282         }
1283         return null;
1284     }
1285 
1286     /* Shell around addComment() to avoid disruption for the moment */
1287     final void comment(const(char)* comment) { addComment(comment); }
1288 
1289     private extern (D) __gshared const(char)*[void*] commentHashTable;
1290 
1291 
1292     /**********************************
1293      * Get ddoc unittest associated with this symbol.
1294      * (only use this with ddoc)
1295      * Returns: ddoc unittest, null if none
1296      */
1297     final UnitTestDeclaration ddocUnittest()
1298     {
1299         if (auto p = cast(void*)this in ddocUnittestHashTable)
1300             return *p;
1301         return null;
1302     }
1303 
1304     /**********************************
1305      * Set ddoc unittest associated with this symbol.
1306      */
1307     final void ddocUnittest(UnitTestDeclaration utd)
1308     {
1309         ddocUnittestHashTable[cast(void*)this] = utd;
1310     }
1311 
1312     private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable;
1313 
1314 
1315     /****************************************
1316      * Returns true if this symbol is defined in a non-root module without instantiation.
1317      */
1318     final bool inNonRoot()
1319     {
1320         Dsymbol s = parent;
1321         for (; s; s = s.toParent())
1322         {
1323             if (auto ti = s.isTemplateInstance())
1324             {
1325                 return false;
1326             }
1327             if (auto m = s.isModule())
1328             {
1329                 if (!m.isRoot())
1330                     return true;
1331                 break;
1332             }
1333         }
1334         return false;
1335     }
1336 
1337     /**
1338      * Deinitializes the global state of the compiler.
1339      *
1340      * This can be used to restore the state set by `_init` to its original
1341      * state.
1342      */
1343     static void deinitialize()
1344     {
1345         commentHashTable = commentHashTable.init;
1346         ddocUnittestHashTable = ddocUnittestHashTable.init;
1347     }
1348 
1349     /************
1350      */
1351     override void accept(Visitor v)
1352     {
1353         v.visit(this);
1354     }
1355 
1356   pure nothrow @safe @nogc:
1357 
1358     // Eliminate need for dynamic_cast
1359     inout(Package)                     isPackage()                     inout { return null; }
1360     inout(Module)                      isModule()                      inout { return null; }
1361     inout(EnumMember)                  isEnumMember()                  inout { return null; }
1362     inout(TemplateDeclaration)         isTemplateDeclaration()         inout { return null; }
1363     inout(TemplateInstance)            isTemplateInstance()            inout { return null; }
1364     inout(TemplateMixin)               isTemplateMixin()               inout { return null; }
1365     inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
1366     inout(Nspace)                      isNspace()                      inout { return null; }
1367     inout(Declaration)                 isDeclaration()                 inout { return null; }
1368     inout(StorageClassDeclaration)     isStorageClassDeclaration()     inout { return null; }
1369     inout(ExpressionDsymbol)           isExpressionDsymbol()           inout { return null; }
1370     inout(AliasAssign)                 isAliasAssign()                 inout { return null; }
1371     inout(ThisDeclaration)             isThisDeclaration()             inout { return null; }
1372     inout(BitFieldDeclaration)         isBitFieldDeclaration()         inout { return null; }
1373     inout(TypeInfoDeclaration)         isTypeInfoDeclaration()         inout { return null; }
1374     inout(TupleDeclaration)            isTupleDeclaration()            inout { return null; }
1375     inout(AliasDeclaration)            isAliasDeclaration()            inout { return null; }
1376     inout(AggregateDeclaration)        isAggregateDeclaration()        inout { return null; }
1377     inout(FuncDeclaration)             isFuncDeclaration()             inout { return null; }
1378     inout(FuncAliasDeclaration)        isFuncAliasDeclaration()        inout { return null; }
1379     inout(OverDeclaration)             isOverDeclaration()             inout { return null; }
1380     inout(FuncLiteralDeclaration)      isFuncLiteralDeclaration()      inout { return null; }
1381     inout(CtorDeclaration)             isCtorDeclaration()             inout { return null; }
1382     inout(PostBlitDeclaration)         isPostBlitDeclaration()         inout { return null; }
1383     inout(DtorDeclaration)             isDtorDeclaration()             inout { return null; }
1384     inout(StaticCtorDeclaration)       isStaticCtorDeclaration()       inout { return null; }
1385     inout(StaticDtorDeclaration)       isStaticDtorDeclaration()       inout { return null; }
1386     inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
1387     inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
1388     inout(InvariantDeclaration)        isInvariantDeclaration()        inout { return null; }
1389     inout(UnitTestDeclaration)         isUnitTestDeclaration()         inout { return null; }
1390     inout(NewDeclaration)              isNewDeclaration()              inout { return null; }
1391     inout(VarDeclaration)              isVarDeclaration()              inout { return null; }
1392     inout(VersionSymbol)               isVersionSymbol()               inout { return null; }
1393     inout(DebugSymbol)                 isDebugSymbol()                 inout { return null; }
1394     inout(ClassDeclaration)            isClassDeclaration()            inout { return null; }
1395     inout(StructDeclaration)           isStructDeclaration()           inout { return null; }
1396     inout(UnionDeclaration)            isUnionDeclaration()            inout { return null; }
1397     inout(InterfaceDeclaration)        isInterfaceDeclaration()        inout { return null; }
1398     inout(ScopeDsymbol)                isScopeDsymbol()                inout { return null; }
1399     inout(ForwardingScopeDsymbol)      isForwardingScopeDsymbol()      inout { return null; }
1400     inout(WithScopeSymbol)             isWithScopeSymbol()             inout { return null; }
1401     inout(ArrayScopeSymbol)            isArrayScopeSymbol()            inout { return null; }
1402     inout(Import)                      isImport()                      inout { return null; }
1403     inout(EnumDeclaration)             isEnumDeclaration()             inout { return null; }
1404     inout(SymbolDeclaration)           isSymbolDeclaration()           inout { return null; }
1405     inout(AttribDeclaration)           isAttribDeclaration()           inout { return null; }
1406     inout(AnonDeclaration)             isAnonDeclaration()             inout { return null; }
1407     inout(CPPNamespaceDeclaration)     isCPPNamespaceDeclaration()     inout { return null; }
1408     inout(VisibilityDeclaration)       isVisibilityDeclaration()       inout { return null; }
1409     inout(OverloadSet)                 isOverloadSet()                 inout { return null; }
1410     inout(MixinDeclaration)            isMixinDeclaration()            inout { return null; }
1411     inout(StaticAssert)                isStaticAssert()                inout { return null; }
1412     inout(StaticIfDeclaration)         isStaticIfDeclaration()         inout { return null; }
1413 }
1414 
1415 /***********************************************************
1416  * Dsymbol that generates a scope
1417  */
1418 extern (C++) class ScopeDsymbol : Dsymbol
1419 {
1420     Dsymbols* members;          // all Dsymbol's in this scope
1421     DsymbolTable symtab;        // members[] sorted into table
1422     uint endlinnum;             // the linnumber of the statement after the scope (0 if unknown)
1423 
1424 private:
1425     /// symbols whose members have been imported, i.e. imported modules and template mixins
1426     Dsymbols* importedScopes;
1427     Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
1428 
1429     import dmd.root.bitarray;
1430     BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1431 
1432 public:
1433     final extern (D) this() nothrow
1434     {
1435     }
1436 
1437     final extern (D) this(Identifier ident) nothrow
1438     {
1439         super(ident);
1440     }
1441 
1442     final extern (D) this(const ref Loc loc, Identifier ident) nothrow
1443     {
1444         super(loc, ident);
1445     }
1446 
1447     override ScopeDsymbol syntaxCopy(Dsymbol s)
1448     {
1449         //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1450         ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1451         sds.comment = comment;
1452         sds.members = arraySyntaxCopy(members);
1453         sds.endlinnum = endlinnum;
1454         return sds;
1455     }
1456 
1457     /*****************************************
1458      * This function is #1 on the list of functions that eat cpu time.
1459      * Be very, very careful about slowing it down.
1460      */
1461     override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1462     {
1463         //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1464         //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1465 
1466         // Look in symbols declared in this module
1467         if (symtab && !(flags & SearchImportsOnly))
1468         {
1469             //printf(" look in locals\n");
1470             auto s1 = symtab.lookup(ident);
1471             if (s1)
1472             {
1473                 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1474                 return s1;
1475             }
1476         }
1477         //printf(" not found in locals\n");
1478 
1479         // Look in imported scopes
1480         if (!importedScopes)
1481             return null;
1482 
1483         //printf(" look in imports\n");
1484         Dsymbol s = null;
1485         OverloadSet a = null;
1486         // Look in imported modules
1487         for (size_t i = 0; i < importedScopes.length; i++)
1488         {
1489             // If private import, don't search it
1490             if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
1491                 continue;
1492             int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
1493             Dsymbol ss = (*importedScopes)[i];
1494             //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1495 
1496             if (ss.isModule())
1497             {
1498                 if (flags & SearchLocalsOnly)
1499                     continue;
1500             }
1501             else // mixin template
1502             {
1503                 if (flags & SearchImportsOnly)
1504                     continue;
1505 
1506                 sflags |= SearchLocalsOnly;
1507             }
1508 
1509             /* Don't find private members if ss is a module
1510              */
1511             Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1512             import dmd.access : symbolIsVisible;
1513             if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1514                 continue;
1515             if (!s)
1516             {
1517                 s = s2;
1518                 if (s && s.isOverloadSet())
1519                     a = mergeOverloadSet(ident, a, s);
1520             }
1521             else if (s2 && s != s2)
1522             {
1523                 if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1524                 {
1525                     /* After following aliases, we found the same
1526                      * symbol, so it's not an ambiguity.  But if one
1527                      * alias is deprecated or less accessible, prefer
1528                      * the other.
1529                      */
1530                     if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
1531                         s = s2;
1532                 }
1533                 else
1534                 {
1535                     /* Two imports of the same module should be regarded as
1536                      * the same.
1537                      */
1538                     Import i1 = s.isImport();
1539                     Import i2 = s2.isImport();
1540                     if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1541                     {
1542                         /* https://issues.dlang.org/show_bug.cgi?id=8668
1543                          * Public selective import adds AliasDeclaration in module.
1544                          * To make an overload set, resolve aliases in here and
1545                          * get actual overload roots which accessible via s and s2.
1546                          */
1547                         s = s.toAlias();
1548                         s2 = s2.toAlias();
1549                         /* If both s2 and s are overloadable (though we only
1550                          * need to check s once)
1551                          */
1552 
1553                         auto so2 = s2.isOverloadSet();
1554                         if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
1555                         {
1556                             if (symbolIsVisible(this, s2))
1557                             {
1558                                 a = mergeOverloadSet(ident, a, s2);
1559                             }
1560                             if (!symbolIsVisible(this, s))
1561                                 s = s2;
1562                             continue;
1563                         }
1564 
1565                         /* Two different overflow sets can have the same members
1566                          * https://issues.dlang.org/show_bug.cgi?id=16709
1567                          */
1568                         auto so = s.isOverloadSet();
1569                         if (so && so2)
1570                         {
1571                             if (so.a.length == so2.a.length)
1572                             {
1573                                 foreach (j; 0 .. so.a.length)
1574                                 {
1575                                     if (so.a[j] !is so2.a[j])
1576                                         goto L1;
1577                                 }
1578                                 continue;  // the same
1579                               L1:
1580                                 {   } // different
1581                             }
1582                         }
1583 
1584                         if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1585                             return null;
1586 
1587                         /* If two imports from C import files, pick first one, as C has global name space
1588                          */
1589                         if (s.isCsymbol() && s2.isCsymbol())
1590                             continue;
1591 
1592                         if (!(flags & IgnoreErrors))
1593                             ScopeDsymbol.multiplyDefined(loc, s, s2);
1594                         break;
1595                     }
1596                 }
1597             }
1598         }
1599         if (s)
1600         {
1601             /* Build special symbol if we had multiple finds
1602              */
1603             if (a)
1604             {
1605                 if (!s.isOverloadSet())
1606                     a = mergeOverloadSet(ident, a, s);
1607                 s = a;
1608             }
1609             //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1610             return s;
1611         }
1612         //printf(" not found in imports\n");
1613         return null;
1614     }
1615 
1616     extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1617     {
1618         if (!os)
1619         {
1620             os = new OverloadSet(ident);
1621             os.parent = this;
1622         }
1623         if (OverloadSet os2 = s.isOverloadSet())
1624         {
1625             // Merge the cross-module overload set 'os2' into 'os'
1626             if (os.a.length == 0)
1627             {
1628                 os.a.setDim(os2.a.length);
1629                 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.length);
1630             }
1631             else
1632             {
1633                 for (size_t i = 0; i < os2.a.length; i++)
1634                 {
1635                     os = mergeOverloadSet(ident, os, os2.a[i]);
1636                 }
1637             }
1638         }
1639         else
1640         {
1641             assert(s.isOverloadable());
1642             /* Don't add to os[] if s is alias of previous sym
1643              */
1644             for (size_t j = 0; j < os.a.length; j++)
1645             {
1646                 Dsymbol s2 = os.a[j];
1647                 if (s.toAlias() == s2.toAlias())
1648                 {
1649                     if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
1650                     {
1651                         os.a[j] = s;
1652                     }
1653                     goto Lcontinue;
1654                 }
1655             }
1656             os.push(s);
1657         Lcontinue:
1658         }
1659         return os;
1660     }
1661 
1662     void importScope(Dsymbol s, Visibility visibility) nothrow
1663     {
1664         //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1665         // No circular or redundant import's
1666         if (s != this)
1667         {
1668             if (!importedScopes)
1669                 importedScopes = new Dsymbols();
1670             else
1671             {
1672                 for (size_t i = 0; i < importedScopes.length; i++)
1673                 {
1674                     Dsymbol ss = (*importedScopes)[i];
1675                     if (ss == s) // if already imported
1676                     {
1677                         if (visibility.kind > visibilities[i])
1678                             visibilities[i] = visibility.kind; // upgrade access
1679                         return;
1680                     }
1681                 }
1682             }
1683             importedScopes.push(s);
1684             visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.length * (visibilities[0]).sizeof);
1685             visibilities[importedScopes.length - 1] = visibility.kind;
1686         }
1687     }
1688 
1689 
1690     /*****************************************
1691      * Returns: the symbols whose members have been imported, i.e. imported modules
1692      * and template mixins.
1693      *
1694      * See_Also: importScope
1695      */
1696     extern (D) final Dsymbols* getImportedScopes() nothrow @nogc @safe pure
1697     {
1698         return importedScopes;
1699     }
1700 
1701     /*****************************************
1702      * Returns: the array of visibilities associated with each imported scope. The
1703      * length of the array matches the imported scopes array.
1704      *
1705      * See_Also: getImportedScopes
1706      */
1707     extern (D) final Visibility.Kind[] getImportVisibilities() nothrow @nogc @safe pure
1708     {
1709         if (!importedScopes)
1710             return null;
1711 
1712         return (() @trusted => visibilities[0 .. importedScopes.length])();
1713     }
1714 
1715     extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
1716     {
1717         auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1718         if (pary.length <= p.tag)
1719             pary.length = p.tag + 1;
1720         (*pary)[p.tag] = true;
1721     }
1722 
1723     bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
1724     {
1725         if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1726             visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1727             return true;
1728         foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1729         {
1730             // only search visible scopes && imported modules should ignore private imports
1731             if (visibility.kind <= visibilities[i] &&
1732                 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
1733                 return true;
1734         }
1735         return false;
1736     }
1737 
1738     override final bool isforwardRef() nothrow
1739     {
1740         return (members is null);
1741     }
1742 
1743     static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1744     {
1745         version (none)
1746         {
1747             printf("ScopeDsymbol::multiplyDefined()\n");
1748             printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1749             printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1750         }
1751         if (loc.isValid())
1752         {
1753             .error(loc, "`%s` matches conflicting symbols:", s1.ident.toChars());
1754             errorSupplemental(s1.loc, "%s `%s`", s1.kind(), s1.toPrettyChars());
1755             errorSupplemental(s2.loc, "%s `%s`", s2.kind(), s2.toPrettyChars());
1756 
1757             static if (0)
1758             {
1759                 if (auto so = s1.isOverloadSet())
1760                 {
1761                     printf("first %p:\n", so);
1762                     foreach (s; so.a[])
1763                     {
1764                         printf("  %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1765                     }
1766                 }
1767                 if (auto so = s2.isOverloadSet())
1768                 {
1769                     printf("second %p:\n", so);
1770                     foreach (s; so.a[])
1771                     {
1772                         printf("  %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1773                     }
1774                 }
1775             }
1776         }
1777         else
1778         {
1779             s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1780         }
1781     }
1782 
1783     override const(char)* kind() const
1784     {
1785         return "ScopeDsymbol";
1786     }
1787 
1788     /*******************************************
1789      * Look for member of the form:
1790      *      const(MemberInfo)[] getMembers(string);
1791      * Returns NULL if not found
1792      */
1793     final FuncDeclaration findGetMembers()
1794     {
1795         Dsymbol s = search_function(this, Id.getmembers);
1796         FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1797         version (none)
1798         {
1799             // Finish
1800             __gshared TypeFunction tfgetmembers;
1801             if (!tfgetmembers)
1802             {
1803                 Scope sc;
1804                 auto parameters = new Parameters();
1805                 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1806                 parameters.push(p);
1807                 Type tret = null;
1808                 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1809                 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1810             }
1811             if (fdx)
1812                 fdx = fdx.overloadExactMatch(tfgetmembers);
1813         }
1814         if (fdx && fdx.isVirtual())
1815             fdx = null;
1816         return fdx;
1817     }
1818 
1819     /********************************
1820      * Insert Dsymbol in table.
1821      * Params:
1822      *   s = symbol to add
1823      * Returns:
1824      *   null if already in table, `s` if inserted
1825      */
1826     Dsymbol symtabInsert(Dsymbol s) nothrow
1827     {
1828         return symtab.insert(s);
1829     }
1830 
1831     /****************************************
1832      * Look up identifier in symbol table.
1833      * Params:
1834      *  s = symbol
1835      *  id = identifier to look up
1836      * Returns:
1837      *   Dsymbol if found, null if not
1838      */
1839     Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
1840     {
1841         return symtab.lookup(id);
1842     }
1843 
1844     /****************************************
1845      * Return true if any of the members are static ctors or static dtors, or if
1846      * any members have members that are.
1847      */
1848     override bool hasStaticCtorOrDtor()
1849     {
1850         if (members)
1851         {
1852             for (size_t i = 0; i < members.length; i++)
1853             {
1854                 Dsymbol member = (*members)[i];
1855                 if (member.hasStaticCtorOrDtor())
1856                     return true;
1857             }
1858         }
1859         return false;
1860     }
1861 
1862     extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1863 
1864     /***************************************
1865      * Expands attribute declarations in members in depth first
1866      * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1867      * member.
1868      * If dg returns !=0, stops and returns that value else returns 0.
1869      * Use this function to avoid the O(N + N^2/2) complexity of
1870      * calculating dim and calling N times getNth.
1871      * Returns:
1872      *  last value returned by dg()
1873      */
1874     extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1875     {
1876         assert(dg);
1877         if (!members)
1878             return 0;
1879         size_t n = pn ? *pn : 0; // take over index
1880         int result = 0;
1881         foreach (size_t i; 0 .. members.length)
1882         {
1883             Dsymbol s = (*members)[i];
1884             if (AttribDeclaration a = s.isAttribDeclaration())
1885                 result = _foreach(sc, a.include(sc), dg, &n);
1886             else if (TemplateMixin tm = s.isTemplateMixin())
1887                 result = _foreach(sc, tm.members, dg, &n);
1888             else if (s.isTemplateInstance())
1889             {
1890             }
1891             else if (s.isUnitTestDeclaration())
1892             {
1893             }
1894             else
1895                 result = dg(n++, s);
1896             if (result)
1897                 break;
1898         }
1899         if (pn)
1900             *pn = n; // update index
1901         return result;
1902     }
1903 
1904     override final inout(ScopeDsymbol) isScopeDsymbol() inout
1905     {
1906         return this;
1907     }
1908 
1909     override void accept(Visitor v)
1910     {
1911         v.visit(this);
1912     }
1913 }
1914 
1915 /***********************************************************
1916  * With statement scope
1917  */
1918 extern (C++) final class WithScopeSymbol : ScopeDsymbol
1919 {
1920     WithStatement withstate;
1921 
1922     extern (D) this(WithStatement withstate) nothrow
1923     {
1924         this.withstate = withstate;
1925     }
1926 
1927     override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1928     {
1929         //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1930         if (flags & SearchImportsOnly)
1931             return null;
1932         // Acts as proxy to the with class declaration
1933         Dsymbol s = null;
1934         Expression eold = null;
1935         for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
1936         {
1937             if (e.op == EXP.scope_)
1938             {
1939                 s = (cast(ScopeExp)e).sds;
1940             }
1941             else if (e.op == EXP.type)
1942             {
1943                 s = e.type.toDsymbol(null);
1944             }
1945             else
1946             {
1947                 Type t = e.type.toBasetype();
1948                 s = t.toDsymbol(null);
1949             }
1950             if (s)
1951             {
1952                 s = s.search(loc, ident, flags);
1953                 if (s)
1954                     return s;
1955             }
1956             eold = e;
1957         }
1958         return null;
1959     }
1960 
1961     override inout(WithScopeSymbol) isWithScopeSymbol() inout
1962     {
1963         return this;
1964     }
1965 
1966     override void accept(Visitor v)
1967     {
1968         v.visit(this);
1969     }
1970 }
1971 
1972 /***********************************************************
1973  * Array Index/Slice scope
1974  */
1975 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1976 {
1977     // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1978     // Discriminated using DYNCAST and, for expressions, also EXP
1979     private RootObject arrayContent;
1980     Scope* sc;
1981 
1982     extern (D) this(Scope* sc, Expression exp) nothrow
1983     {
1984         super(exp.loc, null);
1985         assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
1986         this.sc = sc;
1987         this.arrayContent = exp;
1988     }
1989 
1990     extern (D) this(Scope* sc, TypeTuple type) nothrow
1991     {
1992         this.sc = sc;
1993         this.arrayContent = type;
1994     }
1995 
1996     extern (D) this(Scope* sc, TupleDeclaration td) nothrow
1997     {
1998         this.sc = sc;
1999         this.arrayContent = td;
2000     }
2001 
2002     /// This override is used to solve `$`
2003     override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
2004     {
2005         //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
2006         if (ident != Id.dollar)
2007             return null;
2008 
2009         VarDeclaration* pvar;
2010         Expression ce;
2011 
2012         static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
2013         {
2014 
2015             /* $ gives the number of type entries in the type tuple
2016              */
2017             auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
2018             Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t);
2019             v._init = new ExpInitializer(Loc.initial, e);
2020             v.storage_class |= STC.temp | STC.static_ | STC.const_;
2021             v.dsymbolSemantic(sc);
2022             return v;
2023         }
2024 
2025         const DYNCAST kind = arrayContent.dyncast();
2026         switch (kind) with (DYNCAST)
2027         {
2028         case dsymbol:
2029             TupleDeclaration td = cast(TupleDeclaration) arrayContent;
2030             /* $ gives the number of elements in the tuple
2031              */
2032             auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
2033             Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t);
2034             v._init = new ExpInitializer(Loc.initial, e);
2035             v.storage_class |= STC.temp | STC.static_ | STC.const_;
2036             v.dsymbolSemantic(sc);
2037             return v;
2038         case type:
2039             return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
2040         default:
2041             break;
2042         }
2043         Expression exp = cast(Expression) arrayContent;
2044         if (auto ie = exp.isIndexExp())
2045         {
2046             /* array[index] where index is some function of $
2047              */
2048             pvar = &ie.lengthVar;
2049             ce = ie.e1;
2050         }
2051         else if (auto se = exp.isSliceExp())
2052         {
2053             /* array[lwr .. upr] where lwr or upr is some function of $
2054              */
2055             pvar = &se.lengthVar;
2056             ce = se.e1;
2057         }
2058         else if (auto ae = exp.isArrayExp())
2059         {
2060             /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
2061              * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
2062              */
2063             pvar = &ae.lengthVar;
2064             ce = ae.e1;
2065         }
2066         else
2067         {
2068             /* Didn't find $, look in enclosing scope(s).
2069              */
2070             return null;
2071         }
2072         ce = ce.lastComma();
2073         /* If we are indexing into an array that is really a type
2074          * tuple, rewrite this as an index into a type tuple and
2075          * try again.
2076          */
2077         if (auto te = ce.isTypeExp())
2078         {
2079             if (auto ttp = te.type.isTypeTuple())
2080                 return dollarFromTypeTuple(loc, ttp, sc);
2081         }
2082         /* *pvar is lazily initialized, so if we refer to $
2083          * multiple times, it gets set only once.
2084          */
2085         if (!*pvar) // if not already initialized
2086         {
2087             /* Create variable v and set it to the value of $
2088              */
2089             VarDeclaration v;
2090             Type t;
2091             if (auto tupexp = ce.isTupleExp())
2092             {
2093                 /* It is for an expression tuple, so the
2094                  * length will be a const.
2095                  */
2096                 Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t);
2097                 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
2098                 v.storage_class |= STC.temp | STC.static_ | STC.const_;
2099             }
2100             else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
2101             {
2102                 // Look for opDollar
2103                 assert(exp.op == EXP.array || exp.op == EXP.slice);
2104                 AggregateDeclaration ad = isAggregate(t);
2105                 assert(ad);
2106                 Dsymbol s = ad.search(loc, Id.opDollar);
2107                 if (!s) // no dollar exists -- search in higher scope
2108                     return null;
2109                 s = s.toAlias();
2110                 Expression e = null;
2111                 // Check for multi-dimensional opDollar(dim) template.
2112                 if (TemplateDeclaration td = s.isTemplateDeclaration())
2113                 {
2114                     dinteger_t dim = 0;
2115                     if (exp.op == EXP.array)
2116                     {
2117                         dim = (cast(ArrayExp)exp).currentDimension;
2118                     }
2119                     else if (exp.op == EXP.slice)
2120                     {
2121                         dim = 0; // slices are currently always one-dimensional
2122                     }
2123                     else
2124                     {
2125                         assert(0);
2126                     }
2127                     auto tiargs = new Objects();
2128                     Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
2129                     edim = edim.expressionSemantic(sc);
2130                     tiargs.push(edim);
2131                     e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
2132                 }
2133                 else
2134                 {
2135                     /* opDollar exists, but it's not a template.
2136                      * This is acceptable ONLY for single-dimension indexing.
2137                      * Note that it's impossible to have both template & function opDollar,
2138                      * because both take no arguments.
2139                      */
2140                     if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.length != 1)
2141                     {
2142                         exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
2143                         return null;
2144                     }
2145                     Declaration d = s.isDeclaration();
2146                     assert(d);
2147                     e = new DotVarExp(loc, ce, d);
2148                 }
2149                 e = e.expressionSemantic(sc);
2150                 if (!e.type)
2151                     exp.error("`%s` has no value", e.toChars());
2152                 t = e.type.toBasetype();
2153                 if (t && t.ty == Tfunction)
2154                     e = new CallExp(e.loc, e);
2155                 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
2156                 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
2157             }
2158             else
2159             {
2160                 /* For arrays, $ will either be a compile-time constant
2161                  * (in which case its value in set during constant-folding),
2162                  * or a variable (in which case an expression is created in
2163                  * toir.c).
2164                  */
2165 
2166                 // https://issues.dlang.org/show_bug.cgi?id=16213
2167                 // For static arrays $ is known at compile time,
2168                 // so declare it as a manifest constant.
2169                 auto tsa = ce.type ? ce.type.isTypeSArray() : null;
2170                 if (tsa)
2171                 {
2172                     auto e = new ExpInitializer(loc, tsa.dim);
2173                     v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest);
2174                 }
2175                 else
2176                 {
2177                     auto e = new VoidInitializer(Loc.initial);
2178                     e.type = Type.tsize_t;
2179                     v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
2180                     v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
2181                 }
2182             }
2183             *pvar = v;
2184         }
2185         (*pvar).dsymbolSemantic(sc);
2186         return (*pvar);
2187     }
2188 
2189     override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
2190     {
2191         return this;
2192     }
2193 
2194     override void accept(Visitor v)
2195     {
2196         v.visit(this);
2197     }
2198 }
2199 
2200 /***********************************************************
2201  * Overload Sets
2202  */
2203 extern (C++) final class OverloadSet : Dsymbol
2204 {
2205     Dsymbols a;     // array of Dsymbols
2206 
2207     extern (D) this(Identifier ident, OverloadSet os = null) nothrow
2208     {
2209         super(ident);
2210         if (os)
2211         {
2212             a.pushSlice(os.a[]);
2213         }
2214     }
2215 
2216     void push(Dsymbol s) nothrow
2217     {
2218         a.push(s);
2219     }
2220 
2221     override inout(OverloadSet) isOverloadSet() inout
2222     {
2223         return this;
2224     }
2225 
2226     override const(char)* kind() const
2227     {
2228         return "overloadset";
2229     }
2230 
2231     override void accept(Visitor v)
2232     {
2233         v.visit(this);
2234     }
2235 }
2236 
2237 /***********************************************************
2238  * Forwarding ScopeDsymbol.  Used by ForwardingAttribDeclaration and
2239  * ForwardingScopeDeclaration to forward symbol insertions to another
2240  * scope.  See `dmd.attrib.ForwardingAttribDeclaration` for more
2241  * details.
2242  */
2243 extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
2244 {
2245     extern (D) this() nothrow
2246     {
2247         super();
2248     }
2249 
2250     override Dsymbol symtabInsert(Dsymbol s) nothrow
2251     {
2252         if (auto d = s.isDeclaration())
2253         {
2254             if (d.storage_class & STC.local)
2255             {
2256                 // Symbols with storage class STC.local are not
2257                 // forwarded, but stored in the local symbol
2258                 // table. (Those are the `static foreach` variables.)
2259                 if (!symtab)
2260                 {
2261                     symtab = new DsymbolTable();
2262                 }
2263                 return super.symtabInsert(s); // insert locally
2264             }
2265         }
2266         auto forward = parent.isScopeDsymbol();
2267         assert(forward);
2268         if (!forward.symtab)
2269         {
2270             forward.symtab = new DsymbolTable();
2271         }
2272         // Non-STC.local symbols are forwarded to `forward`.
2273         return forward.symtabInsert(s);
2274     }
2275 
2276     /************************
2277      * This override handles the following two cases:
2278      *     static foreach (i, i; [0]) { ... }
2279      * and
2280      *     static foreach (i; [0]) { enum i = 2; }
2281      */
2282     override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
2283     {
2284         // correctly diagnose clashing foreach loop variables.
2285         if (auto d = s.isDeclaration())
2286         {
2287             if (d.storage_class & STC.local)
2288             {
2289                 if (!symtab)
2290                 {
2291                     symtab = new DsymbolTable();
2292                 }
2293                 return super.symtabLookup(s,id);
2294             }
2295         }
2296         // Declarations within `static foreach` do not clash with
2297         // `static foreach` loop variables.
2298         auto forward = parent.isScopeDsymbol();
2299         assert(forward);
2300         if (!forward.symtab)
2301         {
2302             forward.symtab = new DsymbolTable();
2303         }
2304         return forward.symtabLookup(s,id);
2305     }
2306 
2307     override void importScope(Dsymbol s, Visibility visibility)
2308     {
2309         auto forward = parent.isScopeDsymbol();
2310         assert(forward);
2311         forward.importScope(s, visibility);
2312     }
2313 
2314     override const(char)* kind()const{ return "local scope"; }
2315 
2316     override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
2317     {
2318         return this;
2319     }
2320 
2321 }
2322 
2323 /**
2324  * Class that holds an expression in a Dsymbol wrapper.
2325  * This is not an AST node, but a class used to pass
2326  * an expression as a function parameter of type Dsymbol.
2327  */
2328 extern (C++) final class ExpressionDsymbol : Dsymbol
2329 {
2330     Expression exp;
2331     this(Expression exp) nothrow
2332     {
2333         super();
2334         this.exp = exp;
2335     }
2336 
2337     override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
2338     {
2339         return this;
2340     }
2341 }
2342 
2343 /**********************************************
2344  * Encapsulate assigning to an alias:
2345  *      `identifier = type;`
2346  *      `identifier = symbol;`
2347  * where `identifier` is an AliasDeclaration in scope.
2348  */
2349 extern (C++) final class AliasAssign : Dsymbol
2350 {
2351     Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
2352     Type type;        /// replace previous RHS of AliasDeclaration with `type`
2353     Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
2354                       /// only one of type and aliassym can be != null
2355 
2356     extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
2357     {
2358         super(loc, null);
2359         this.ident = ident;
2360         this.type = type;
2361         this.aliassym = aliassym;
2362     }
2363 
2364     override AliasAssign syntaxCopy(Dsymbol s)
2365     {
2366         assert(!s);
2367         AliasAssign aa = new AliasAssign(loc, ident,
2368                 type     ? type.syntaxCopy()         : null,
2369                 aliassym ? aliassym.syntaxCopy(null) : null);
2370         return aa;
2371     }
2372 
2373     override inout(AliasAssign) isAliasAssign() inout
2374     {
2375         return this;
2376     }
2377 
2378     override const(char)* kind() const
2379     {
2380         return "alias assignment";
2381     }
2382 
2383     override void accept(Visitor v)
2384     {
2385         v.visit(this);
2386     }
2387 }
2388 
2389 /***********************************************************
2390  * Table of Dsymbol's
2391  */
2392 extern (C++) final class DsymbolTable : RootObject
2393 {
2394     AssocArray!(Identifier, Dsymbol) tab;
2395 
2396   nothrow:
2397 
2398    /***************************
2399     * Look up Identifier in symbol table
2400     * Params:
2401     *   ident = identifer to look up
2402     * Returns:
2403     *   Dsymbol if found, null if not
2404     */
2405     Dsymbol lookup(const Identifier ident)
2406     {
2407         //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2408         return tab[ident];
2409     }
2410 
2411     /**********
2412      * Replace existing symbol in symbol table with `s`.
2413      * If it's not there, add it.
2414      * Params:
2415      *   s = replacement symbol with same identifier
2416      */
2417     void update(Dsymbol s)
2418     {
2419         *tab.getLvalue(s.ident) = s;
2420     }
2421 
2422     /**************************
2423      * Insert Dsymbol in table.
2424      * Params:
2425      *   s = symbol to add
2426      * Returns:
2427      *   null if already in table, `s` if inserted
2428      */
2429     Dsymbol insert(Dsymbol s)
2430     {
2431         return insert(s.ident, s);
2432     }
2433 
2434     /**************************
2435      * Insert Dsymbol in table.
2436      * Params:
2437      *   ident = identifier to serve as index
2438      *   s = symbol to add
2439      * Returns:
2440      *   null if already in table, `s` if inserted
2441      */
2442     Dsymbol insert(const Identifier ident, Dsymbol s)
2443     {
2444         //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2445         Dsymbol* ps = tab.getLvalue(ident);
2446         if (*ps)
2447             return null; // already in table
2448         *ps = s;
2449         return s;
2450     }
2451 
2452     /*****************
2453      * Returns:
2454      *  number of symbols in symbol table
2455      */
2456     size_t length() const pure
2457     {
2458         return tab.length;
2459     }
2460 }
2461 
2462 /**********************************************
2463  * ImportC tag symbols sit in a parallel symbol table,
2464  * so that this C code works:
2465  * ---
2466  * struct S { a; };
2467  * int S;
2468  * struct S s;
2469  * ---
2470  * But there are relatively few such tag symbols, so that would be
2471  * a waste of memory and complexity. An additional problem is we'd like the D side
2472  * to find the tag symbols with ordinary lookup, not lookup in both
2473  * tables, if the tag symbol is not conflicting with an ordinary symbol.
2474  * The solution is to put the tag symbols that conflict into an associative
2475  * array, indexed by the address of the ordinary symbol that conflicts with it.
2476  * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2477  * A side effect of our approach is that D code cannot access a tag symbol that is
2478  * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2479  * has mentioned it when importing C headers. If someone wants to do it,
2480  * too bad so sad. Change the C code.
2481  * This function fixes up the symbol table when faced with adding a new symbol
2482  * `s` when there is an existing symbol `s2` with the same name.
2483  * C also allows forward and prototype declarations of tag symbols,
2484  * this function merges those.
2485  * Params:
2486  *      sc = context
2487  *      s = symbol to add to symbol table
2488  *      s2 = existing declaration
2489  *      sds = symbol table
2490  * Returns:
2491  *      if s and s2 are successfully put in symbol table then return the merged symbol,
2492  *      null if they conflict
2493  */
2494 Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2495 {
2496     enum log = false;
2497     if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
2498     if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2499     auto sd = s.isScopeDsymbol(); // new declaration
2500     auto sd2 = s2.isScopeDsymbol(); // existing declaration
2501 
2502     static if (log) void print(EnumDeclaration sd)
2503     {
2504         printf("members: %p\n", sd.members);
2505         printf("symtab: %p\n", sd.symtab);
2506         printf("endlinnum: %d\n", sd.endlinnum);
2507         printf("type: %s\n", sd.type.toChars());
2508         printf("memtype: %s\n", sd.memtype.toChars());
2509     }
2510 
2511     if (!sd2)
2512     {
2513         /* Look in tag table
2514          */
2515         if (log) printf(" look in tag table\n");
2516         if (auto p = cast(void*)s2 in sc._module.tagSymTab)
2517         {
2518             Dsymbol s2tag = *p;
2519             sd2 = s2tag.isScopeDsymbol();
2520             assert(sd2);        // only tags allowed in tag symbol table
2521         }
2522     }
2523 
2524     if (sd && sd2) // `s` is a tag, `sd2` is the same tag
2525     {
2526         if (log) printf(" tag is already defined\n");
2527 
2528         if (sd.kind() != sd2.kind())  // being enum/struct/union must match
2529             return null;              // conflict
2530 
2531         /* Not a redeclaration if one is a forward declaration.
2532          * Move members to the first declared type, which is sd2.
2533          */
2534         if (sd2.members)
2535         {
2536             if (!sd.members)
2537                 return sd2;  // ignore the sd redeclaration
2538         }
2539         else if (sd.members)
2540         {
2541             sd2.members = sd.members; // transfer definition to sd2
2542             sd.members = null;
2543             if (auto ed2 = sd2.isEnumDeclaration())
2544             {
2545                 auto ed = sd.isEnumDeclaration();
2546                 if (ed.memtype != ed2.memtype)
2547                     return null;        // conflict
2548 
2549                 // transfer ed's members to sd2
2550                 ed2.members.foreachDsymbol( (s)
2551                 {
2552                     if (auto em = s.isEnumMember())
2553                         em.ed = ed2;
2554                 });
2555 
2556                 ed2.type = ed.type;
2557                 ed2.memtype = ed.memtype;
2558                 ed2.added = false;
2559             }
2560             return sd2;
2561         }
2562         else
2563             return sd2; // ignore redeclaration
2564     }
2565     else if (sd) // `s` is a tag, `s2` is not
2566     {
2567         if (log) printf(" s is tag, s2 is not\n");
2568         /* add `s` as tag indexed by s2
2569          */
2570         sc._module.tagSymTab[cast(void*)s2] = s;
2571         return s;
2572     }
2573     else if (s2 is sd2) // `s2` is a tag, `s` is not
2574     {
2575         if (log) printf(" s2 is tag, s is not\n");
2576         /* replace `s2` in symbol table with `s`,
2577          * then add `s2` as tag indexed by `s`
2578          */
2579         sds.symtab.update(s);
2580         sc._module.tagSymTab[cast(void*)s] = s2;
2581         return s;
2582     }
2583     // neither s2 nor s is a tag
2584     if (log) printf(" collision\n");
2585     return null;
2586 }
2587 
2588 
2589 /**********************************************
2590  * ImportC allows redeclarations of C variables, functions and typedefs.
2591  *    extern int x;
2592  *    int x = 3;
2593  * and:
2594  *    extern void f();
2595  *    void f() { }
2596  * Attempt to merge them.
2597  * Params:
2598  *      sc = context
2599  *      s = symbol to add to symbol table
2600  *      s2 = existing declaration
2601  *      sds = symbol table
2602  * Returns:
2603  *      if s and s2 are successfully put in symbol table then return the merged symbol,
2604  *      null if they conflict
2605  */
2606 Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2607 {
2608     enum log = false;
2609     if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
2610     if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2611 
2612     static Dsymbol collision()
2613     {
2614         if (log) printf(" collision\n");
2615         return null;
2616     }
2617     /*
2618     Handle merging declarations with asm("foo") and their definitions
2619     */
2620     static void mangleWrangle(Declaration oldDecl, Declaration newDecl)
2621     {
2622         if (oldDecl && newDecl)
2623         {
2624             newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null;
2625         }
2626     }
2627 
2628     auto vd = s.isVarDeclaration(); // new declaration
2629     auto vd2 = s2.isVarDeclaration(); // existing declaration
2630 
2631     if (vd && vd.isCmacro())
2632         return vd2;
2633 
2634     assert(!(vd2 && vd2.isCmacro()));
2635 
2636     if (vd && vd2)
2637     {
2638         /* if one is `static` and the other isn't, the result is undefined
2639          * behavior, C11 6.2.2.7
2640          */
2641         if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
2642             return collision();
2643 
2644         const i1 =  vd._init && ! vd._init.isVoidInitializer();
2645         const i2 = vd2._init && !vd2._init.isVoidInitializer();
2646 
2647         if (i1 && i2)
2648             return collision();         // can't both have initializers
2649 
2650         mangleWrangle(vd2, vd);
2651 
2652         if (i1)                         // vd is the definition
2653         {
2654             vd2.storage_class |= STC.extern_;  // so toObjFile() won't emit it
2655             sds.symtab.update(vd);      // replace vd2 with the definition
2656             return vd;
2657         }
2658 
2659         /* BUG: the types should match, which needs semantic() to be run on it
2660          *    extern int x;
2661          *    int x;  // match
2662          *    typedef int INT;
2663          *    INT x;  // match
2664          *    long x; // collision
2665          * We incorrectly ignore these collisions
2666          */
2667         return vd2;
2668     }
2669 
2670     auto fd = s.isFuncDeclaration(); // new declaration
2671     auto fd2 = s2.isFuncDeclaration(); // existing declaration
2672     if (fd && fd2)
2673     {
2674         /* if one is `static` and the other isn't, the result is undefined
2675          * behavior, C11 6.2.2.7
2676          * However, match what gcc allows:
2677          *    static int sun1(); int sun1() { return 0; }
2678          * and:
2679          *    static int sun2() { return 0; } int sun2();
2680          * Both produce a static function.
2681          *
2682          * Both of these should fail:
2683          *    int sun3(); static int sun3() { return 0; }
2684          * and:
2685          *    int sun4() { return 0; } static int sun4();
2686          */
2687         // if adding `static`
2688         if (   fd.storage_class & STC.static_ &&
2689             !(fd2.storage_class & STC.static_))
2690         {
2691             return collision();
2692         }
2693 
2694         if (fd.fbody && fd2.fbody)
2695             return collision();         // can't both have bodies
2696 
2697         mangleWrangle(fd2, fd);
2698 
2699         if (fd.fbody)                   // fd is the definition
2700         {
2701             if (log) printf(" replace existing with new\n");
2702             sds.symtab.update(fd);      // replace fd2 in symbol table with fd
2703             fd.overnext = fd2;
2704 
2705             /* If fd2 is covering a tag symbol, then fd has to cover the same one
2706              */
2707             auto ps = cast(void*)fd2 in sc._module.tagSymTab;
2708             if (ps)
2709                 sc._module.tagSymTab[cast(void*)fd] = *ps;
2710 
2711             return fd;
2712         }
2713 
2714         /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2715          * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
2716          */
2717         fd2.overloadInsert(fd);
2718 
2719         return fd2;
2720     }
2721 
2722     auto td  = s.isAliasDeclaration();  // new declaration
2723     auto td2 = s2.isAliasDeclaration(); // existing declaration
2724     if (td && td2)
2725     {
2726         /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2727          * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2728          */
2729         return td2;
2730     }
2731 
2732     return collision();
2733 }