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