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