Home | History | Annotate | Line # | Download | only in dmd
dsymbol.d revision 1.1.1.1
      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  */
     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  */
     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 
    115     extern (D) this(uint old) nothrow
    116     {
    117         this.oldgag = old;
    118     }
    119 
    120     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      */
    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      */
    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 
    258     final extern (D) this() nothrow
    259     {
    260         //printf("Dsymbol::Dsymbol(%p)\n", this);
    261         loc = Loc(null, 0, 0);
    262     }
    263 
    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 
    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 
    278     static Dsymbol create(Identifier ident) nothrow
    279     {
    280         return new Dsymbol(ident);
    281     }
    282 
    283     override const(char)* toChars() const
    284     {
    285         return ident ? ident.toChars() : "__anonymous";
    286     }
    287 
    288     // helper to print fully qualified (template) arguments
    289     const(char)* toPrettyCharsHelper()
    290     {
    291         return toChars();
    292     }
    293 
    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 
    302     final const(char)* locToChars()
    303     {
    304         return getLoc().toChars();
    305     }
    306 
    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 
    322     final bool isAnonymous() const
    323     {
    324         return ident is null || ident.isAnonymous;
    325     }
    326 
    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     {
    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 
    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 
    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 
    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     {
    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 
    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 
    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 
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    559     final inout(Dsymbol) toParent() inout
    560     {
    561         return parent ? parent.pastMixin() : null;
    562     }
    563 
    564     /// ditto
    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
    573     final inout(Dsymbol) toParentDecl() inout
    574     {
    575         return toParentDeclImpl(false);
    576     }
    577 
    578     /// ditto
    579     final inout(Dsymbol) toParentLocal() inout
    580     {
    581         return toParentDeclImpl(true);
    582     }
    583 
    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 
    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     {
    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.
    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 
    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()
    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      */
    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 
    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 
    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      */
    776     Dsymbol toAlias()
    777     {
    778         return this;
    779     }
    780 
    781     /*********************************
    782      * Resolve recursive tuple expansion in eponymous template.
    783      */
    784     Dsymbol toAlias2()
    785     {
    786         return toAlias();
    787     }
    788 
    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      */
    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 
    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 
    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      */
    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 
    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      */
    985     uinteger_t size(const ref Loc loc)
    986     {
    987         error("Dsymbol `%s` has no size", toChars());
    988         return SIZE_INVALID;
    989     }
    990 
    991     bool isforwardRef()
    992     {
    993         return false;
    994     }
    995 
    996     // is a 'this' required to access the member
    997     inout(AggregateDeclaration) isThis() inout
    998     {
    999         return null;
   1000     }
   1001 
   1002     // is Dsymbol exported?
   1003     bool isExport() const
   1004     {
   1005         return false;
   1006     }
   1007 
   1008     // is Dsymbol imported?
   1009     bool isImportedSymbol() const
   1010     {
   1011         return false;
   1012     }
   1013 
   1014     // is Dsymbol deprecated?
   1015     bool isDeprecated() @safe @nogc pure nothrow const
   1016     {
   1017         return false;
   1018     }
   1019 
   1020     bool isOverloadable() const
   1021     {
   1022         return false;
   1023     }
   1024 
   1025     // is this a LabelDsymbol()?
   1026     LabelDsymbol isLabel()
   1027     {
   1028         return null;
   1029     }
   1030 
   1031     /// Returns an AggregateDeclaration when toParent() is that.
   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.
   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.
   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.
   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?
   1068     final ClassDeclaration isClassMember()
   1069     {
   1070         auto ad = isMember();
   1071         return ad ? ad.isClassDeclaration() : null;
   1072     }
   1073 
   1074     // is this a type?
   1075     Type getType()
   1076     {
   1077         return null;
   1078     }
   1079 
   1080     // need a 'this' pointer?
   1081     bool needThis()
   1082     {
   1083         return false;
   1084     }
   1085 
   1086     /*************************************
   1087      */
   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      */
   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      */
   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      */
   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 
   1181     void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
   1182     {
   1183     }
   1184 
   1185     /*****************************************
   1186      * Is Dsymbol a variable that contains pointers?
   1187      */
   1188     bool hasPointers()
   1189     {
   1190         //printf("Dsymbol::hasPointers() %s\n", toChars());
   1191         return false;
   1192     }
   1193 
   1194     bool hasStaticCtorOrDtor()
   1195     {
   1196         //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
   1197         return false;
   1198     }
   1199 
   1200     void addLocalClass(ClassDeclarations*)
   1201     {
   1202     }
   1203 
   1204     void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
   1205     {
   1206     }
   1207 
   1208     void checkCtorConstInit()
   1209     {
   1210     }
   1211 
   1212     /****************************************
   1213      * Add documentation comment to Dsymbol.
   1214      * Ignore NULL comments.
   1215      */
   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
   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 */
   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      */
   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      */
   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      */
   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      */
   1305     static void deinitialize()
   1306     {
   1307         commentHashTable = commentHashTable.init;
   1308         ddocUnittestHashTable = ddocUnittestHashTable.init;
   1309     }
   1310 
   1311     /************
   1312      */
   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
   1321     inout(Package)                     isPackage()                     inout { return null; }
   1322     inout(Module)                      isModule()                      inout { return null; }
   1323     inout(EnumMember)                  isEnumMember()                  inout { return null; }
   1324     inout(TemplateDeclaration)         isTemplateDeclaration()         inout { return null; }
   1325     inout(TemplateInstance)            isTemplateInstance()            inout { return null; }
   1326     inout(TemplateMixin)               isTemplateMixin()               inout { return null; }
   1327     inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
   1328     inout(Nspace)                      isNspace()                      inout { return null; }
   1329     inout(Declaration)                 isDeclaration()                 inout { return null; }
   1330     inout(StorageClassDeclaration)     isStorageClassDeclaration()     inout { return null; }
   1331     inout(ExpressionDsymbol)           isExpressionDsymbol()           inout { return null; }
   1332     inout(AliasAssign)                 isAliasAssign()                 inout { return null; }
   1333     inout(ThisDeclaration)             isThisDeclaration()             inout { return null; }
   1334     inout(BitFieldDeclaration)         isBitFieldDeclaration()         inout { return null; }
   1335     inout(TypeInfoDeclaration)         isTypeInfoDeclaration()         inout { return null; }
   1336     inout(TupleDeclaration)            isTupleDeclaration()            inout { return null; }
   1337     inout(AliasDeclaration)            isAliasDeclaration()            inout { return null; }
   1338     inout(AggregateDeclaration)        isAggregateDeclaration()        inout { return null; }
   1339     inout(FuncDeclaration)             isFuncDeclaration()             inout { return null; }
   1340     inout(FuncAliasDeclaration)        isFuncAliasDeclaration()        inout { return null; }
   1341     inout(OverDeclaration)             isOverDeclaration()             inout { return null; }
   1342     inout(FuncLiteralDeclaration)      isFuncLiteralDeclaration()      inout { return null; }
   1343     inout(CtorDeclaration)             isCtorDeclaration()             inout { return null; }
   1344     inout(PostBlitDeclaration)         isPostBlitDeclaration()         inout { return null; }
   1345     inout(DtorDeclaration)             isDtorDeclaration()             inout { return null; }
   1346     inout(StaticCtorDeclaration)       isStaticCtorDeclaration()       inout { return null; }
   1347     inout(StaticDtorDeclaration)       isStaticDtorDeclaration()       inout { return null; }
   1348     inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
   1349     inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
   1350     inout(InvariantDeclaration)        isInvariantDeclaration()        inout { return null; }
   1351     inout(UnitTestDeclaration)         isUnitTestDeclaration()         inout { return null; }
   1352     inout(NewDeclaration)              isNewDeclaration()              inout { return null; }
   1353     inout(VarDeclaration)              isVarDeclaration()              inout { return null; }
   1354     inout(VersionSymbol)               isVersionSymbol()               inout { return null; }
   1355     inout(DebugSymbol)                 isDebugSymbol()                 inout { return null; }
   1356     inout(ClassDeclaration)            isClassDeclaration()            inout { return null; }
   1357     inout(StructDeclaration)           isStructDeclaration()           inout { return null; }
   1358     inout(UnionDeclaration)            isUnionDeclaration()            inout { return null; }
   1359     inout(InterfaceDeclaration)        isInterfaceDeclaration()        inout { return null; }
   1360     inout(ScopeDsymbol)                isScopeDsymbol()                inout { return null; }
   1361     inout(ForwardingScopeDsymbol)      isForwardingScopeDsymbol()      inout { return null; }
   1362     inout(WithScopeSymbol)             isWithScopeSymbol()             inout { return null; }
   1363     inout(ArrayScopeSymbol)            isArrayScopeSymbol()            inout { return null; }
   1364     inout(Import)                      isImport()                      inout { return null; }
   1365     inout(EnumDeclaration)             isEnumDeclaration()             inout { return null; }
   1366     inout(SymbolDeclaration)           isSymbolDeclaration()           inout { return null; }
   1367     inout(AttribDeclaration)           isAttribDeclaration()           inout { return null; }
   1368     inout(AnonDeclaration)             isAnonDeclaration()             inout { return null; }
   1369     inout(CPPNamespaceDeclaration)     isCPPNamespaceDeclaration()     inout { return null; }
   1370     inout(VisibilityDeclaration)       isVisibilityDeclaration()       inout { return null; }
   1371     inout(OverloadSet)                 isOverloadSet()                 inout { return null; }
   1372     inout(CompileDeclaration)          isCompileDeclaration()          inout { return null; }
   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:
   1394     final extern (D) this() nothrow
   1395     {
   1396     }
   1397 
   1398     final extern (D) this(Identifier ident) nothrow
   1399     {
   1400         super(ident);
   1401     }
   1402 
   1403     final extern (D) this(const ref Loc loc, Identifier ident) nothrow
   1404     {
   1405         super(loc, ident);
   1406     }
   1407 
   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 
   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 
   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 
   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 
   1667     override final bool isforwardRef() nothrow
   1668     {
   1669         return (members is null);
   1670     }
   1671 
   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 
   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      */
   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      */
   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      */
   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      */
   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 
   1833     override final inout(ScopeDsymbol) isScopeDsymbol() inout
   1834     {
   1835         return this;
   1836     }
   1837 
   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 
   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 
   1890     override inout(WithScopeSymbol) isWithScopeSymbol() inout
   1891     {
   1892         return this;
   1893     }
   1894 
   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 
   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 
   1919     extern (D) this(Scope* sc, TypeTuple type) nothrow
   1920     {
   1921         this.sc = sc;
   1922         this.arrayContent = type;
   1923     }
   1924 
   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 
   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 
   2104     override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
   2105     {
   2106         return this;
   2107     }
   2108 
   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 
   2131     void push(Dsymbol s) nothrow
   2132     {
   2133         a.push(s);
   2134     }
   2135 
   2136     override inout(OverloadSet) isOverloadSet() inout
   2137     {
   2138         return this;
   2139     }
   2140 
   2141     override const(char)* kind() const
   2142     {
   2143         return "overloadset";
   2144     }
   2145 
   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;
   2165     extern (D) this(ScopeDsymbol forward) nothrow
   2166     {
   2167         super(null);
   2168         this.forward = forward;
   2169     }
   2170 
   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      */
   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 
   2226     override void importScope(Dsymbol s, Visibility visibility)
   2227     {
   2228         forward.importScope(s, visibility);
   2229     }
   2230 
   2231     override const(char)* kind()const{ return "local scope"; }
   2232 
   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;
   2248     this(Expression exp) nothrow
   2249     {
   2250         super();
   2251         this.exp = exp;
   2252     }
   2253 
   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 
   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 
   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 
   2290     override inout(AliasAssign) isAliasAssign() inout
   2291     {
   2292         return this;
   2293     }
   2294 
   2295     override const(char)* kind() const
   2296     {
   2297         return "alias assignment";
   2298     }
   2299 
   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     */
   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      */
   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      */
   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      */
   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      */
   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  */
   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  */
   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