Home | History | Annotate | Line # | Download | only in dmd
attrib.d revision 1.1
      1 /**
      2  * Defines declarations of various attributes.
      3  *
      4  * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
      5  * Among them are:
      6  * - Alignment (`align(8)`)
      7  * - User defined attributes (`@UDA`)
      8  * - Function Attributes (`@safe`)
      9  * - Storage classes (`static`, `__gshared`)
     10  * - Mixin declarations  (`mixin("int x;")`)
     11  * - Conditional compilation (`static if`, `static foreach`)
     12  * - Linkage (`extern(C)`)
     13  * - Anonymous structs / unions
     14  * - Protection (`private`, `public`)
     15  * - Deprecated declarations (`@deprecated`)
     16  *
     17  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
     18  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
     19  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
     20  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
     21  * Documentation:  https://dlang.org/phobos/dmd_attrib.html
     22  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
     23  */
     24 
     25 module dmd.attrib;
     26 
     27 import dmd.aggregate;
     28 import dmd.arraytypes;
     29 import dmd.astenums;
     30 import dmd.cond;
     31 import dmd.declaration;
     32 import dmd.dmodule;
     33 import dmd.dscope;
     34 import dmd.dsymbol;
     35 import dmd.dsymbolsem : dsymbolSemantic;
     36 import dmd.expression;
     37 import dmd.expressionsem;
     38 import dmd.func;
     39 import dmd.globals;
     40 import dmd.hdrgen : visibilityToBuffer;
     41 import dmd.id;
     42 import dmd.identifier;
     43 import dmd.mtype;
     44 import dmd.objc; // for objc.addSymbols
     45 import dmd.common.outbuffer;
     46 import dmd.root.array; // for each
     47 import dmd.tokens;
     48 import dmd.visitor;
     49 
     50 /***********************************************************
     51  * Abstract attribute applied to Dsymbol's used as a common
     52  * ancestor for storage classes (StorageClassDeclaration),
     53  * linkage (LinkageDeclaration) and others.
     54  */
     55 extern (C++) abstract class AttribDeclaration : Dsymbol
     56 {
     57     Dsymbols* decl;     /// Dsymbol's affected by this AttribDeclaration
     58 
     59     extern (D) this(Dsymbols* decl)
     60     {
     61         this.decl = decl;
     62     }
     63 
     64     extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
     65     {
     66         super(loc, ident);
     67         this.decl = decl;
     68     }
     69 
     70     Dsymbols* include(Scope* sc)
     71     {
     72         if (errors)
     73             return null;
     74 
     75         return decl;
     76     }
     77 
     78     /****************************************
     79      * Create a new scope if one or more given attributes
     80      * are different from the sc's.
     81      * If the returned scope != sc, the caller should pop
     82      * the scope after it used.
     83      */
     84     extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
     85         CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
     86         AlignDeclaration aligndecl, PragmaDeclaration inlining)
     87     {
     88         Scope* sc2 = sc;
     89         if (stc != sc.stc ||
     90             linkage != sc.linkage ||
     91             cppmangle != sc.cppmangle ||
     92             explicitVisibility != sc.explicitVisibility ||
     93             visibility != sc.visibility ||
     94             aligndecl !is sc.aligndecl ||
     95             inlining != sc.inlining)
     96         {
     97             // create new one for changes
     98             sc2 = sc.copy();
     99             sc2.stc = stc;
    100             sc2.linkage = linkage;
    101             sc2.cppmangle = cppmangle;
    102             sc2.visibility = visibility;
    103             sc2.explicitVisibility = explicitVisibility;
    104             sc2.aligndecl = aligndecl;
    105             sc2.inlining = inlining;
    106         }
    107         return sc2;
    108     }
    109 
    110     /****************************************
    111      * A hook point to supply scope for members.
    112      * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
    113      */
    114     Scope* newScope(Scope* sc)
    115     {
    116         return sc;
    117     }
    118 
    119     override void addMember(Scope* sc, ScopeDsymbol sds)
    120     {
    121         Dsymbols* d = include(sc);
    122         if (d)
    123         {
    124             Scope* sc2 = newScope(sc);
    125             d.foreachDsymbol( s => s.addMember(sc2, sds) );
    126             if (sc2 != sc)
    127                 sc2.pop();
    128         }
    129     }
    130 
    131     override void setScope(Scope* sc)
    132     {
    133         Dsymbols* d = include(sc);
    134         //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
    135         if (d)
    136         {
    137             Scope* sc2 = newScope(sc);
    138             d.foreachDsymbol( s => s.setScope(sc2) );
    139             if (sc2 != sc)
    140                 sc2.pop();
    141         }
    142     }
    143 
    144     override void importAll(Scope* sc)
    145     {
    146         Dsymbols* d = include(sc);
    147         //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
    148         if (d)
    149         {
    150             Scope* sc2 = newScope(sc);
    151             d.foreachDsymbol( s => s.importAll(sc2) );
    152             if (sc2 != sc)
    153                 sc2.pop();
    154         }
    155     }
    156 
    157     override void addComment(const(char)* comment)
    158     {
    159         //printf("AttribDeclaration::addComment %s\n", comment);
    160         if (comment)
    161         {
    162             include(null).foreachDsymbol( s => s.addComment(comment) );
    163         }
    164     }
    165 
    166     override const(char)* kind() const
    167     {
    168         return "attribute";
    169     }
    170 
    171     override bool oneMember(Dsymbol* ps, Identifier ident)
    172     {
    173         Dsymbols* d = include(null);
    174         return Dsymbol.oneMembers(d, ps, ident);
    175     }
    176 
    177     override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
    178     {
    179         include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
    180     }
    181 
    182     override final bool hasPointers()
    183     {
    184         return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
    185     }
    186 
    187     override final bool hasStaticCtorOrDtor()
    188     {
    189         return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
    190     }
    191 
    192     override final void checkCtorConstInit()
    193     {
    194         include(null).foreachDsymbol( s => s.checkCtorConstInit() );
    195     }
    196 
    197     /****************************************
    198      */
    199     override final void addLocalClass(ClassDeclarations* aclasses)
    200     {
    201         include(null).foreachDsymbol( s => s.addLocalClass(aclasses) );
    202     }
    203 
    204     override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
    205     {
    206         objc.addSymbols(this, classes, categories);
    207     }
    208 
    209     override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
    210     {
    211         return this;
    212     }
    213 
    214     override void accept(Visitor v)
    215     {
    216         v.visit(this);
    217     }
    218 }
    219 
    220 /***********************************************************
    221  * Storage classes applied to Dsymbols, e.g. `const int i;`
    222  *
    223  * <stc> <decl...>
    224  */
    225 extern (C++) class StorageClassDeclaration : AttribDeclaration
    226 {
    227     StorageClass stc;
    228 
    229     extern (D) this(StorageClass stc, Dsymbols* decl)
    230     {
    231         super(decl);
    232         this.stc = stc;
    233     }
    234 
    235     override StorageClassDeclaration syntaxCopy(Dsymbol s)
    236     {
    237         assert(!s);
    238         return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
    239     }
    240 
    241     override Scope* newScope(Scope* sc)
    242     {
    243         StorageClass scstc = sc.stc;
    244         /* These sets of storage classes are mutually exclusive,
    245          * so choose the innermost or most recent one.
    246          */
    247         if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
    248             scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
    249         if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
    250             scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
    251         if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
    252             scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
    253         if (stc & (STC.gshared | STC.shared_))
    254             scstc &= ~(STC.gshared | STC.shared_);
    255         if (stc & (STC.safe | STC.trusted | STC.system))
    256             scstc &= ~(STC.safe | STC.trusted | STC.system);
    257         scstc |= stc;
    258         //printf("scstc = x%llx\n", scstc);
    259         return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
    260             sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
    261     }
    262 
    263     override final bool oneMember(Dsymbol* ps, Identifier ident)
    264     {
    265         bool t = Dsymbol.oneMembers(decl, ps, ident);
    266         if (t && *ps)
    267         {
    268             /* This is to deal with the following case:
    269              * struct Tick {
    270              *   template to(T) { const T to() { ... } }
    271              * }
    272              * For eponymous function templates, the 'const' needs to get attached to 'to'
    273              * before the semantic analysis of 'to', so that template overloading based on the
    274              * 'this' pointer can be successful.
    275              */
    276             FuncDeclaration fd = (*ps).isFuncDeclaration();
    277             if (fd)
    278             {
    279                 /* Use storage_class2 instead of storage_class otherwise when we do .di generation
    280                  * we'll wind up with 'const const' rather than 'const'.
    281                  */
    282                 /* Don't think we need to worry about mutually exclusive storage classes here
    283                  */
    284                 fd.storage_class2 |= stc;
    285             }
    286         }
    287         return t;
    288     }
    289 
    290     override void addMember(Scope* sc, ScopeDsymbol sds)
    291     {
    292         Dsymbols* d = include(sc);
    293         if (d)
    294         {
    295             Scope* sc2 = newScope(sc);
    296 
    297             d.foreachDsymbol( (s)
    298             {
    299                 //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
    300                 // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
    301                 if (auto decl = s.isDeclaration())
    302                 {
    303                     decl.storage_class |= stc & STC.local;
    304                     if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
    305                     {
    306                         sdecl.stc |= stc & STC.local;
    307                     }
    308                 }
    309                 s.addMember(sc2, sds);
    310             });
    311 
    312             if (sc2 != sc)
    313                 sc2.pop();
    314         }
    315 
    316     }
    317 
    318     override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
    319     {
    320         return this;
    321     }
    322 
    323     override void accept(Visitor v)
    324     {
    325         v.visit(this);
    326     }
    327 }
    328 
    329 /***********************************************************
    330  * Deprecation with an additional message applied to Dsymbols,
    331  * e.g. `deprecated("Superseeded by foo") int bar;`.
    332  * (Note that `deprecated int bar;` is currently represented as a
    333  * StorageClassDeclaration with STC.deprecated_)
    334  *
    335  * `deprecated(<msg>) <decl...>`
    336  */
    337 extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
    338 {
    339     Expression msg;         /// deprecation message
    340     const(char)* msgstr;    /// cached string representation of msg
    341 
    342     extern (D) this(Expression msg, Dsymbols* decl)
    343     {
    344         super(STC.deprecated_, decl);
    345         this.msg = msg;
    346     }
    347 
    348     override DeprecatedDeclaration syntaxCopy(Dsymbol s)
    349     {
    350         assert(!s);
    351         return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
    352     }
    353 
    354     /**
    355      * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
    356      *
    357      * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
    358      * in any function overriding `newScope`), then set the `Scope`'s depdecl.
    359      *
    360      * Returns:
    361      *   Always a new scope, to use for this `DeprecatedDeclaration`'s members.
    362      */
    363     override Scope* newScope(Scope* sc)
    364     {
    365         auto scx = super.newScope(sc);
    366         // The enclosing scope is deprecated as well
    367         if (scx == sc)
    368             scx = sc.push();
    369         scx.depdecl = this;
    370         return scx;
    371     }
    372 
    373     override void setScope(Scope* sc)
    374     {
    375         //printf("DeprecatedDeclaration::setScope() %p\n", this);
    376         if (decl)
    377             Dsymbol.setScope(sc); // for forward reference
    378         return AttribDeclaration.setScope(sc);
    379     }
    380 
    381     override void accept(Visitor v)
    382     {
    383         v.visit(this);
    384     }
    385 }
    386 
    387 /***********************************************************
    388  * Linkage attribute applied to Dsymbols, e.g.
    389  * `extern(C) void foo()`.
    390  *
    391  * `extern(<linkage>) <decl...>`
    392  */
    393 extern (C++) final class LinkDeclaration : AttribDeclaration
    394 {
    395     LINK linkage; /// either explicitly set or `default_`
    396 
    397     extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl)
    398     {
    399         super(loc, null, decl);
    400         //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
    401         this.linkage = linkage;
    402     }
    403 
    404     static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
    405     {
    406         return new LinkDeclaration(loc, p, decl);
    407     }
    408 
    409     override LinkDeclaration syntaxCopy(Dsymbol s)
    410     {
    411         assert(!s);
    412         return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
    413     }
    414 
    415     override Scope* newScope(Scope* sc)
    416     {
    417         return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
    418             sc.aligndecl, sc.inlining);
    419     }
    420 
    421     override const(char)* toChars() const
    422     {
    423         return toString().ptr;
    424     }
    425 
    426     extern(D) override const(char)[] toString() const
    427     {
    428         return "extern ()";
    429     }
    430 
    431     override void accept(Visitor v)
    432     {
    433         v.visit(this);
    434     }
    435 }
    436 
    437 /***********************************************************
    438  * Attribute declaring whether an external aggregate should be mangled as
    439  * a struct or class in C++, e.g. `extern(C++, struct) class C { ... }`.
    440  * This is required for correct name mangling on MSVC targets,
    441  * see cppmanglewin.d for details.
    442  *
    443  * `extern(C++, <cppmangle>) <decl...>`
    444  */
    445 extern (C++) final class CPPMangleDeclaration : AttribDeclaration
    446 {
    447     CPPMANGLE cppmangle;
    448 
    449     extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl)
    450     {
    451         super(loc, null, decl);
    452         //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
    453         this.cppmangle = cppmangle;
    454     }
    455 
    456     override CPPMangleDeclaration syntaxCopy(Dsymbol s)
    457     {
    458         assert(!s);
    459         return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
    460     }
    461 
    462     override Scope* newScope(Scope* sc)
    463     {
    464         return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
    465             sc.aligndecl, sc.inlining);
    466     }
    467 
    468     override void setScope(Scope* sc)
    469     {
    470         if (decl)
    471             Dsymbol.setScope(sc); // for forward reference
    472         return AttribDeclaration.setScope(sc);
    473     }
    474 
    475     override const(char)* toChars() const
    476     {
    477         return toString().ptr;
    478     }
    479 
    480     extern(D) override const(char)[] toString() const
    481     {
    482         return "extern ()";
    483     }
    484 
    485     override void accept(Visitor v)
    486     {
    487         v.visit(this);
    488     }
    489 }
    490 
    491 /**
    492  * A node to represent an `extern(C++)` namespace attribute
    493  *
    494  * There are two ways to declarate a symbol as member of a namespace:
    495  * `Nspace` and `CPPNamespaceDeclaration`.
    496  * The former creates a scope for the symbol, and inject them in the
    497  * parent scope at the same time.
    498  * The later, this class, has no semantic implications and is only
    499  * used for mangling.
    500  * Additionally, this class allows one to use reserved identifiers
    501  * (D keywords) in the namespace.
    502  *
    503  * A `CPPNamespaceDeclaration` can be created from an `Identifier`
    504  * (already resolved) or from an `Expression`, which is CTFE-ed
    505  * and can be either a `TupleExp`, in which can additional
    506  * `CPPNamespaceDeclaration` nodes are created, or a `StringExp`.
    507  *
    508  * Note that this class, like `Nspace`, matches only one identifier
    509  * part of a namespace. For the namespace `"foo::bar"`,
    510  * the will be a `CPPNamespaceDeclaration` with its `ident`
    511  * set to `"bar"`, and its `namespace` field pointing to another
    512  * `CPPNamespaceDeclaration` with its `ident` set to `"foo"`.
    513  */
    514 extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
    515 {
    516     /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
    517     Expression exp;
    518 
    519     extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
    520     {
    521         super(loc, ident, decl);
    522     }
    523 
    524     extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
    525     {
    526         super(loc, null, decl);
    527         this.exp = exp;
    528     }
    529 
    530     extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
    531                     CPPNamespaceDeclaration parent)
    532     {
    533         super(loc, ident, decl);
    534         this.exp = exp;
    535         this.cppnamespace = parent;
    536     }
    537 
    538     override CPPNamespaceDeclaration syntaxCopy(Dsymbol s)
    539     {
    540         assert(!s);
    541         return new CPPNamespaceDeclaration(
    542             this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
    543     }
    544 
    545     /**
    546      * Returns:
    547      *   A copy of the parent scope, with `this` as `namespace` and C++ linkage
    548      */
    549     override Scope* newScope(Scope* sc)
    550     {
    551         auto scx = sc.copy();
    552         scx.linkage = LINK.cpp;
    553         scx.namespace = this;
    554         return scx;
    555     }
    556 
    557     override const(char)* toChars() const
    558     {
    559         return toString().ptr;
    560     }
    561 
    562     extern(D) override const(char)[] toString() const
    563     {
    564         return "extern (C++, `namespace`)";
    565     }
    566 
    567     override void accept(Visitor v)
    568     {
    569         v.visit(this);
    570     }
    571 
    572     override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
    573 }
    574 
    575 /***********************************************************
    576  * Visibility declaration for Dsymbols, e.g. `public int i;`
    577  *
    578  * `<visibility> <decl...>` or
    579  * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
    580  */
    581 extern (C++) final class VisibilityDeclaration : AttribDeclaration
    582 {
    583     Visibility visibility;          /// the visibility
    584     Identifier[] pkg_identifiers;   /// identifiers for `package(foo.bar)` or null
    585 
    586     /**
    587      * Params:
    588      *  loc = source location of attribute token
    589      *  visibility = visibility attribute data
    590      *  decl = declarations which are affected by this visibility attribute
    591      */
    592     extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl)
    593     {
    594         super(loc, null, decl);
    595         this.visibility = visibility;
    596         //printf("decl = %p\n", decl);
    597     }
    598 
    599     /**
    600      * Params:
    601      *  loc = source location of attribute token
    602      *  pkg_identifiers = list of identifiers for a qualified package name
    603      *  decl = declarations which are affected by this visibility attribute
    604      */
    605     extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
    606     {
    607         super(loc, null, decl);
    608         this.visibility.kind = Visibility.Kind.package_;
    609         this.pkg_identifiers = pkg_identifiers;
    610         if (pkg_identifiers.length > 0)
    611         {
    612             Dsymbol tmp;
    613             Package.resolve(pkg_identifiers, &tmp, null);
    614             visibility.pkg = tmp ? tmp.isPackage() : null;
    615         }
    616     }
    617 
    618     override VisibilityDeclaration syntaxCopy(Dsymbol s)
    619     {
    620         assert(!s);
    621 
    622         if (visibility.kind == Visibility.Kind.package_)
    623             return new VisibilityDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
    624         else
    625             return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
    626     }
    627 
    628     override Scope* newScope(Scope* sc)
    629     {
    630         if (pkg_identifiers)
    631             dsymbolSemantic(this, sc);
    632         return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
    633     }
    634 
    635     override void addMember(Scope* sc, ScopeDsymbol sds)
    636     {
    637         if (pkg_identifiers)
    638         {
    639             Dsymbol tmp;
    640             Package.resolve(pkg_identifiers, &tmp, null);
    641             visibility.pkg = tmp ? tmp.isPackage() : null;
    642             pkg_identifiers = null;
    643         }
    644         if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
    645         {
    646             Module m = sc._module;
    647 
    648             // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
    649             // each package's .isModule() properites are equal.
    650             //
    651             // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
    652             // This breaks package declarations of the package in question if they are declared in
    653             // the same package.d file, which _do_ have a module associated with them, and hence a non-null
    654             // isModule()
    655             if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
    656             {
    657                 Package pkg = m.parent ? m.parent.isPackage() : null;
    658                 if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
    659                     error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true));
    660             }
    661         }
    662         return AttribDeclaration.addMember(sc, sds);
    663     }
    664 
    665     override const(char)* kind() const
    666     {
    667         return "visibility attribute";
    668     }
    669 
    670     override const(char)* toPrettyChars(bool)
    671     {
    672         assert(visibility.kind > Visibility.Kind.undefined);
    673         OutBuffer buf;
    674         visibilityToBuffer(&buf, visibility);
    675         return buf.extractChars();
    676     }
    677 
    678     override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
    679     {
    680         return this;
    681     }
    682 
    683     override void accept(Visitor v)
    684     {
    685         v.visit(this);
    686     }
    687 }
    688 
    689 /***********************************************************
    690  * Alignment attribute for aggregates, members and variables.
    691  *
    692  * `align(<ealign>) <decl...>` or
    693  * `align <decl...>` if `ealign` is null
    694  */
    695 extern (C++) final class AlignDeclaration : AttribDeclaration
    696 {
    697     Expressions* exps;                              /// Expression(s) yielding the desired alignment,
    698                                                     /// the largest value wins
    699     /// the actual alignment is Unknown until it's either set to the value of `ealign`
    700     /// or the default if `ealign` is null ( / an error ocurred)
    701     structalign_t salign;
    702 
    703 
    704     extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
    705     {
    706         super(loc, null, decl);
    707         if (exp)
    708         {
    709             exps = new Expressions();
    710             exps.push(exp);
    711         }
    712     }
    713 
    714     extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl)
    715     {
    716         super(loc, null, decl);
    717         this.exps = exps;
    718     }
    719 
    720     extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl)
    721     {
    722         super(loc, null, decl);
    723         this.salign = salign;
    724     }
    725 
    726     override AlignDeclaration syntaxCopy(Dsymbol s)
    727     {
    728         assert(!s);
    729         return new AlignDeclaration(loc,
    730             Expression.arraySyntaxCopy(exps),
    731             Dsymbol.arraySyntaxCopy(decl));
    732     }
    733 
    734     override Scope* newScope(Scope* sc)
    735     {
    736         return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
    737     }
    738 
    739     override void accept(Visitor v)
    740     {
    741         v.visit(this);
    742     }
    743 }
    744 
    745 /***********************************************************
    746  * An anonymous struct/union (defined by `isunion`).
    747  */
    748 extern (C++) final class AnonDeclaration : AttribDeclaration
    749 {
    750     bool isunion;           /// whether it's a union
    751     int sem;                /// 1 if successful semantic()
    752     uint anonoffset;        /// offset of anonymous struct
    753     uint anonstructsize;    /// size of anonymous struct
    754     uint anonalignsize;     /// size of anonymous struct for alignment purposes
    755 
    756     extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl)
    757     {
    758         super(loc, null, decl);
    759         this.isunion = isunion;
    760     }
    761 
    762     override AnonDeclaration syntaxCopy(Dsymbol s)
    763     {
    764         assert(!s);
    765         return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
    766     }
    767 
    768     override void setScope(Scope* sc)
    769     {
    770         if (decl)
    771             Dsymbol.setScope(sc);
    772         return AttribDeclaration.setScope(sc);
    773     }
    774 
    775     override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
    776     {
    777         //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
    778         if (decl)
    779         {
    780             /* This works by treating an AnonDeclaration as an aggregate 'member',
    781              * so in order to place that member we need to compute the member's
    782              * size and alignment.
    783              */
    784             size_t fieldstart = ad.fields.dim;
    785 
    786             /* Hackishly hijack ad's structsize and alignsize fields
    787              * for use in our fake anon aggregate member.
    788              */
    789             uint savestructsize = ad.structsize;
    790             uint savealignsize = ad.alignsize;
    791             ad.structsize = 0;
    792             ad.alignsize = 0;
    793 
    794             FieldState fs;
    795             decl.foreachDsymbol( (s)
    796             {
    797                 s.setFieldOffset(ad, fs, this.isunion);
    798                 if (this.isunion)
    799                     fs.offset = 0;
    800             });
    801 
    802             /* https://issues.dlang.org/show_bug.cgi?id=13613
    803              * If the fields in this.members had been already
    804              * added in ad.fields, just update *poffset for the subsequent
    805              * field offset calculation.
    806              */
    807             if (fieldstart == ad.fields.dim)
    808             {
    809                 ad.structsize = savestructsize;
    810                 ad.alignsize = savealignsize;
    811                 fieldState.offset = ad.structsize;
    812                 return;
    813             }
    814 
    815             anonstructsize = ad.structsize;
    816             anonalignsize = ad.alignsize;
    817             ad.structsize = savestructsize;
    818             ad.alignsize = savealignsize;
    819 
    820             // 0 sized structs are set to 1 byte
    821             if (anonstructsize == 0)
    822             {
    823                 anonstructsize = 1;
    824                 anonalignsize = 1;
    825             }
    826 
    827             assert(_scope);
    828             auto alignment = _scope.alignment();
    829 
    830             /* Given the anon 'member's size and alignment,
    831              * go ahead and place it.
    832              */
    833             anonoffset = AggregateDeclaration.placeField(
    834                 &fieldState.offset,
    835                 anonstructsize, anonalignsize, alignment,
    836                 &ad.structsize, &ad.alignsize,
    837                 isunion);
    838 
    839             // Add to the anon fields the base offset of this anonymous aggregate
    840             //printf("anon fields, anonoffset = %d\n", anonoffset);
    841             foreach (const i; fieldstart .. ad.fields.dim)
    842             {
    843                 VarDeclaration v = ad.fields[i];
    844                 //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
    845                 v.offset += anonoffset;
    846             }
    847         }
    848     }
    849 
    850     override const(char)* kind() const
    851     {
    852         return (isunion ? "anonymous union" : "anonymous struct");
    853     }
    854 
    855     override inout(AnonDeclaration) isAnonDeclaration() inout
    856     {
    857         return this;
    858     }
    859 
    860     override void accept(Visitor v)
    861     {
    862         v.visit(this);
    863     }
    864 }
    865 
    866 /***********************************************************
    867  * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
    868  * but not PragmaStatement's like `pragma(msg, "hello");`.
    869  *
    870  * pragma(<ident>, <args>)
    871  */
    872 extern (C++) final class PragmaDeclaration : AttribDeclaration
    873 {
    874     Expressions* args;      /// parameters of this pragma
    875 
    876     extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl)
    877     {
    878         super(loc, ident, decl);
    879         this.args = args;
    880     }
    881 
    882     override PragmaDeclaration syntaxCopy(Dsymbol s)
    883     {
    884         //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
    885         assert(!s);
    886         return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
    887     }
    888 
    889     override Scope* newScope(Scope* sc)
    890     {
    891         if (ident == Id.Pinline)
    892         {
    893             // We keep track of this pragma inside scopes,
    894             // then it's evaluated on demand in function semantic
    895             return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
    896         }
    897         if (ident == Id.printf || ident == Id.scanf)
    898         {
    899             auto sc2 = sc.push();
    900 
    901             if (ident == Id.printf)
    902                 // Override previous setting, never let both be set
    903                 sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf;
    904             else
    905                 sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf;
    906 
    907             return sc2;
    908         }
    909         return sc;
    910     }
    911 
    912     PINLINE evalPragmaInline(Scope* sc)
    913     {
    914         if (!args || args.dim == 0)
    915             return PINLINE.default_;
    916 
    917         Expression e = (*args)[0];
    918         if (!e.type)
    919         {
    920 
    921             sc = sc.startCTFE();
    922             e = e.expressionSemantic(sc);
    923             e = resolveProperties(sc, e);
    924             sc = sc.endCTFE();
    925             e = e.ctfeInterpret();
    926             e = e.toBoolean(sc);
    927             if (e.isErrorExp())
    928                 error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars());
    929             (*args)[0] = e;
    930         }
    931 
    932         const opt = e.toBool();
    933         if (opt.isEmpty())
    934             return PINLINE.default_;
    935         else if (opt.get())
    936             return PINLINE.always;
    937         else
    938             return PINLINE.never;
    939     }
    940 
    941     override const(char)* kind() const
    942     {
    943         return "pragma";
    944     }
    945 
    946     override void accept(Visitor v)
    947     {
    948         v.visit(this);
    949     }
    950 }
    951 
    952 /***********************************************************
    953  * A conditional compilation declaration, used for `version`
    954  * / `debug` and specialized for `static if`.
    955  *
    956  * <condition> { <decl...> } else { <elsedecl> }
    957  */
    958 extern (C++) class ConditionalDeclaration : AttribDeclaration
    959 {
    960     Condition condition;    /// condition deciding whether decl or elsedecl applies
    961     Dsymbols* elsedecl;     /// array of Dsymbol's for else block
    962 
    963     extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
    964     {
    965         super(loc, null, decl);
    966         //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
    967         this.condition = condition;
    968         this.elsedecl = elsedecl;
    969     }
    970 
    971     override ConditionalDeclaration syntaxCopy(Dsymbol s)
    972     {
    973         assert(!s);
    974         return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
    975     }
    976 
    977     override final bool oneMember(Dsymbol* ps, Identifier ident)
    978     {
    979         //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
    980         if (condition.inc != Include.notComputed)
    981         {
    982             Dsymbols* d = condition.include(null) ? decl : elsedecl;
    983             return Dsymbol.oneMembers(d, ps, ident);
    984         }
    985         else
    986         {
    987             bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null);
    988             *ps = null;
    989             return res;
    990         }
    991     }
    992 
    993     // Decide if 'then' or 'else' code should be included
    994     override Dsymbols* include(Scope* sc)
    995     {
    996         //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
    997 
    998         if (errors)
    999             return null;
   1000 
   1001         assert(condition);
   1002         return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
   1003     }
   1004 
   1005     override final void addComment(const(char)* comment)
   1006     {
   1007         /* Because addComment is called by the parser, if we called
   1008          * include() it would define a version before it was used.
   1009          * But it's no problem to drill down to both decl and elsedecl,
   1010          * so that's the workaround.
   1011          */
   1012         if (comment)
   1013         {
   1014             decl    .foreachDsymbol( s => s.addComment(comment) );
   1015             elsedecl.foreachDsymbol( s => s.addComment(comment) );
   1016         }
   1017     }
   1018 
   1019     override void setScope(Scope* sc)
   1020     {
   1021         include(sc).foreachDsymbol( s => s.setScope(sc) );
   1022     }
   1023 
   1024     override void accept(Visitor v)
   1025     {
   1026         v.visit(this);
   1027     }
   1028 }
   1029 
   1030 /***********************************************************
   1031  * `<scopesym> {
   1032  *      static if (<condition>) { <decl> } else { <elsedecl> }
   1033  * }`
   1034  */
   1035 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
   1036 {
   1037     ScopeDsymbol scopesym;          /// enclosing symbol (e.g. module) where symbols will be inserted
   1038     private bool addisdone = false; /// true if members have been added to scope
   1039     private bool onStack = false;   /// true if a call to `include` is currently active
   1040 
   1041     extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
   1042     {
   1043         super(loc, condition, decl, elsedecl);
   1044         //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
   1045     }
   1046 
   1047     override StaticIfDeclaration syntaxCopy(Dsymbol s)
   1048     {
   1049         assert(!s);
   1050         return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
   1051     }
   1052 
   1053     /****************************************
   1054      * Different from other AttribDeclaration subclasses, include() call requires
   1055      * the completion of addMember and setScope phases.
   1056      */
   1057     override Dsymbols* include(Scope* sc)
   1058     {
   1059         //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
   1060 
   1061         if (errors || onStack)
   1062             return null;
   1063         onStack = true;
   1064         scope(exit) onStack = false;
   1065 
   1066         if (sc && condition.inc == Include.notComputed)
   1067         {
   1068             assert(scopesym); // addMember is already done
   1069             assert(_scope); // setScope is already done
   1070             Dsymbols* d = ConditionalDeclaration.include(_scope);
   1071             if (d && !addisdone)
   1072             {
   1073                 // Add members lazily.
   1074                 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
   1075 
   1076                 // Set the member scopes lazily.
   1077                 d.foreachDsymbol( s => s.setScope(_scope) );
   1078 
   1079                 addisdone = true;
   1080             }
   1081             return d;
   1082         }
   1083         else
   1084         {
   1085             return ConditionalDeclaration.include(sc);
   1086         }
   1087     }
   1088 
   1089     override void addMember(Scope* sc, ScopeDsymbol sds)
   1090     {
   1091         //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
   1092         /* This is deferred until the condition evaluated later (by the include() call),
   1093          * so that expressions in the condition can refer to declarations
   1094          * in the same scope, such as:
   1095          *
   1096          * template Foo(int i)
   1097          * {
   1098          *     const int j = i + 1;
   1099          *     static if (j == 3)
   1100          *         const int k;
   1101          * }
   1102          */
   1103         this.scopesym = sds;
   1104     }
   1105 
   1106     override void setScope(Scope* sc)
   1107     {
   1108         // do not evaluate condition before semantic pass
   1109         // But do set the scope, in case we need it for forward referencing
   1110         Dsymbol.setScope(sc);
   1111     }
   1112 
   1113     override void importAll(Scope* sc)
   1114     {
   1115         // do not evaluate condition before semantic pass
   1116     }
   1117 
   1118     override const(char)* kind() const
   1119     {
   1120         return "static if";
   1121     }
   1122 
   1123     override void accept(Visitor v)
   1124     {
   1125         v.visit(this);
   1126     }
   1127 }
   1128 
   1129 /***********************************************************
   1130  * Static foreach at declaration scope, like:
   1131  *     static foreach (i; [0, 1, 2]){ }
   1132  */
   1133 
   1134 extern (C++) final class StaticForeachDeclaration : AttribDeclaration
   1135 {
   1136     StaticForeach sfe; /// contains `static foreach` expansion logic
   1137 
   1138     ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
   1139 
   1140     /++
   1141      `include` can be called multiple times, but a `static foreach`
   1142      should be expanded at most once.  Achieved by caching the result
   1143      of the first call.  We need both `cached` and `cache`, because
   1144      `null` is a valid value for `cache`.
   1145      +/
   1146     bool onStack = false;
   1147     bool cached = false;
   1148     Dsymbols* cache = null;
   1149 
   1150     extern (D) this(StaticForeach sfe, Dsymbols* decl)
   1151     {
   1152         super(sfe.loc, null, decl);
   1153         this.sfe = sfe;
   1154     }
   1155 
   1156     override StaticForeachDeclaration syntaxCopy(Dsymbol s)
   1157     {
   1158         assert(!s);
   1159         return new StaticForeachDeclaration(
   1160             sfe.syntaxCopy(),
   1161             Dsymbol.arraySyntaxCopy(decl));
   1162     }
   1163 
   1164     override bool oneMember(Dsymbol* ps, Identifier ident)
   1165     {
   1166         // Required to support IFTI on a template that contains a
   1167         // `static foreach` declaration.  `super.oneMember` calls
   1168         // include with a `null` scope.  As `static foreach` requires
   1169         // the scope for expansion, `oneMember` can only return a
   1170         // precise result once `static foreach` has been expanded.
   1171         if (cached)
   1172         {
   1173             return super.oneMember(ps, ident);
   1174         }
   1175         *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
   1176         return false;
   1177     }
   1178 
   1179     override Dsymbols* include(Scope* sc)
   1180     {
   1181         if (errors || onStack)
   1182             return null;
   1183         if (cached)
   1184         {
   1185             assert(!onStack);
   1186             return cache;
   1187         }
   1188         onStack = true;
   1189         scope(exit) onStack = false;
   1190 
   1191         if (_scope)
   1192         {
   1193             sfe.prepare(_scope); // lower static foreach aggregate
   1194         }
   1195         if (!sfe.ready())
   1196         {
   1197             return null; // TODO: ok?
   1198         }
   1199 
   1200         // expand static foreach
   1201         import dmd.statementsem: makeTupleForeach;
   1202         Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
   1203         if (d) // process generated declarations
   1204         {
   1205             // Add members lazily.
   1206             d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
   1207 
   1208             // Set the member scopes lazily.
   1209             d.foreachDsymbol( s => s.setScope(_scope) );
   1210         }
   1211         cached = true;
   1212         cache = d;
   1213         return d;
   1214     }
   1215 
   1216     override void addMember(Scope* sc, ScopeDsymbol sds)
   1217     {
   1218         // used only for caching the enclosing symbol
   1219         this.scopesym = sds;
   1220     }
   1221 
   1222     override void addComment(const(char)* comment)
   1223     {
   1224         // do nothing
   1225         // change this to give semantics to documentation comments on static foreach declarations
   1226     }
   1227 
   1228     override void setScope(Scope* sc)
   1229     {
   1230         // do not evaluate condition before semantic pass
   1231         // But do set the scope, in case we need it for forward referencing
   1232         Dsymbol.setScope(sc);
   1233     }
   1234 
   1235     override void importAll(Scope* sc)
   1236     {
   1237         // do not evaluate aggregate before semantic pass
   1238     }
   1239 
   1240     override const(char)* kind() const
   1241     {
   1242         return "static foreach";
   1243     }
   1244 
   1245     override void accept(Visitor v)
   1246     {
   1247         v.visit(this);
   1248     }
   1249 }
   1250 
   1251 /***********************************************************
   1252  * Collection of declarations that stores foreach index variables in a
   1253  * local symbol table.  Other symbols declared within are forwarded to
   1254  * another scope, like:
   1255  *
   1256  *      static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
   1257  *      { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
   1258  *          mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
   1259  *      }
   1260  *
   1261  *      static foreach (i; 0.. 10)
   1262  *      {
   1263  *          pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
   1264  *      }
   1265  *
   1266  *      static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
   1267  *
   1268  * A StaticForeachDeclaration generates one
   1269  * ForwardingAttribDeclaration for each expansion of its body.  The
   1270  * AST of the ForwardingAttribDeclaration contains both the `static
   1271  * foreach` variables and the respective copy of the `static foreach`
   1272  * body.  The functionality is achieved by using a
   1273  * ForwardingScopeDsymbol as the parent symbol for the generated
   1274  * declarations.
   1275  */
   1276 
   1277 extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
   1278 {
   1279     ForwardingScopeDsymbol sym = null;
   1280 
   1281     this(Dsymbols* decl)
   1282     {
   1283         super(decl);
   1284         sym = new ForwardingScopeDsymbol(null);
   1285         sym.symtab = new DsymbolTable();
   1286     }
   1287 
   1288     /**************************************
   1289      * Use the ForwardingScopeDsymbol as the parent symbol for members.
   1290      */
   1291     override Scope* newScope(Scope* sc)
   1292     {
   1293         return sc.push(sym);
   1294     }
   1295 
   1296     /***************************************
   1297      * Lazily initializes the scope to forward to.
   1298      */
   1299     override void addMember(Scope* sc, ScopeDsymbol sds)
   1300     {
   1301         parent = sym.parent = sym.forward = sds;
   1302         return super.addMember(sc, sym);
   1303     }
   1304 
   1305     override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
   1306     {
   1307         return this;
   1308     }
   1309 
   1310     override void accept(Visitor v)
   1311     {
   1312         v.visit(this);
   1313     }
   1314 }
   1315 
   1316 
   1317 /***********************************************************
   1318  * Mixin declarations, like:
   1319  *      mixin("int x");
   1320  * https://dlang.org/spec/module.html#mixin-declaration
   1321  */
   1322 extern (C++) final class CompileDeclaration : AttribDeclaration
   1323 {
   1324     Expressions* exps;
   1325     ScopeDsymbol scopesym;
   1326     bool compiled;
   1327 
   1328     extern (D) this(const ref Loc loc, Expressions* exps)
   1329     {
   1330         super(loc, null, null);
   1331         //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
   1332         this.exps = exps;
   1333     }
   1334 
   1335     override CompileDeclaration syntaxCopy(Dsymbol s)
   1336     {
   1337         //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
   1338         return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
   1339     }
   1340 
   1341     override void addMember(Scope* sc, ScopeDsymbol sds)
   1342     {
   1343         //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
   1344         this.scopesym = sds;
   1345     }
   1346 
   1347     override void setScope(Scope* sc)
   1348     {
   1349         Dsymbol.setScope(sc);
   1350     }
   1351 
   1352     override const(char)* kind() const
   1353     {
   1354         return "mixin";
   1355     }
   1356 
   1357     override inout(CompileDeclaration) isCompileDeclaration() inout
   1358     {
   1359         return this;
   1360     }
   1361 
   1362     override void accept(Visitor v)
   1363     {
   1364         v.visit(this);
   1365     }
   1366 }
   1367 
   1368 /***********************************************************
   1369  * User defined attributes look like:
   1370  *      @foo(args, ...)
   1371  *      @(args, ...)
   1372  */
   1373 extern (C++) final class UserAttributeDeclaration : AttribDeclaration
   1374 {
   1375     Expressions* atts;
   1376 
   1377     extern (D) this(Expressions* atts, Dsymbols* decl)
   1378     {
   1379         super(decl);
   1380         this.atts = atts;
   1381     }
   1382 
   1383     override UserAttributeDeclaration syntaxCopy(Dsymbol s)
   1384     {
   1385         //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
   1386         assert(!s);
   1387         return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
   1388     }
   1389 
   1390     override Scope* newScope(Scope* sc)
   1391     {
   1392         Scope* sc2 = sc;
   1393         if (atts && atts.dim)
   1394         {
   1395             // create new one for changes
   1396             sc2 = sc.copy();
   1397             sc2.userAttribDecl = this;
   1398         }
   1399         return sc2;
   1400     }
   1401 
   1402     override void setScope(Scope* sc)
   1403     {
   1404         //printf("UserAttributeDeclaration::setScope() %p\n", this);
   1405         if (decl)
   1406             Dsymbol.setScope(sc); // for forward reference of UDAs
   1407         return AttribDeclaration.setScope(sc);
   1408     }
   1409 
   1410     extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
   1411     {
   1412         Expressions* udas;
   1413         if (!udas1 || udas1.dim == 0)
   1414             udas = udas2;
   1415         else if (!udas2 || udas2.dim == 0)
   1416             udas = udas1;
   1417         else
   1418         {
   1419             /* Create a new tuple that combines them
   1420              * (do not append to left operand, as this is a copy-on-write operation)
   1421              */
   1422             udas = new Expressions(2);
   1423             (*udas)[0] = new TupleExp(Loc.initial, udas1);
   1424             (*udas)[1] = new TupleExp(Loc.initial, udas2);
   1425         }
   1426         return udas;
   1427     }
   1428 
   1429     Expressions* getAttributes()
   1430     {
   1431         if (auto sc = _scope)
   1432         {
   1433             _scope = null;
   1434             arrayExpressionSemantic(atts, sc);
   1435         }
   1436         auto exps = new Expressions();
   1437         if (userAttribDecl && userAttribDecl !is this)
   1438             exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
   1439         if (atts && atts.dim)
   1440             exps.push(new TupleExp(Loc.initial, atts));
   1441         return exps;
   1442     }
   1443 
   1444     override const(char)* kind() const
   1445     {
   1446         return "UserAttribute";
   1447     }
   1448 
   1449     override void accept(Visitor v)
   1450     {
   1451         v.visit(this);
   1452     }
   1453 
   1454     /**
   1455      * Check if the provided expression references `core.attribute.gnuAbiTag`
   1456      *
   1457      * This should be called after semantic has been run on the expression.
   1458      * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
   1459      *
   1460      * Params:
   1461      *   e = Expression to check (usually from `UserAttributeDeclaration.atts`)
   1462      *
   1463      * Returns:
   1464      *   `true` if the expression references the compiler-recognized `gnuAbiTag`
   1465      */
   1466     static bool isGNUABITag(Expression e)
   1467     {
   1468         if (global.params.cplusplus < CppStdRevision.cpp11)
   1469             return false;
   1470 
   1471         auto ts = e.type ? e.type.isTypeStruct() : null;
   1472         if (!ts)
   1473             return false;
   1474         if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
   1475             return false;
   1476         // Can only be defined in druntime
   1477         Module m = ts.sym.parent.isModule();
   1478         if (!m || !m.isCoreModule(Id.attribute))
   1479             return false;
   1480         return true;
   1481     }
   1482 
   1483     /**
   1484      * Called from a symbol's semantic to check if `gnuAbiTag` UDA
   1485      * can be applied to them
   1486      *
   1487      * Directly emits an error if the UDA doesn't work with this symbol
   1488      *
   1489      * Params:
   1490      *   sym = symbol to check for `gnuAbiTag`
   1491      *   linkage = Linkage of the symbol (Declaration.link or sc.link)
   1492      */
   1493     static void checkGNUABITag(Dsymbol sym, LINK linkage)
   1494     {
   1495         if (global.params.cplusplus < CppStdRevision.cpp11)
   1496             return;
   1497 
   1498         foreachUdaNoSemantic(sym, (exp) {
   1499             if (isGNUABITag(exp))
   1500             {
   1501                 if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
   1502                 {
   1503                     exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
   1504                     sym.errors = true;
   1505                 }
   1506                 else if (linkage != LINK.cpp)
   1507                 {
   1508                     exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
   1509                     sym.errors = true;
   1510                 }
   1511                 // Only one `@gnuAbiTag` is allowed by semantic2
   1512                 return 1; // break
   1513             }
   1514             return 0; // continue
   1515         });
   1516     }
   1517 }
   1518 
   1519 /**
   1520  * Returns `true` if the given symbol is a symbol declared in
   1521  * `core.attribute` and has the given identifier.
   1522  *
   1523  * This is used to determine if a symbol is a UDA declared in
   1524  * `core.attribute`.
   1525  *
   1526  * Params:
   1527  *  sym = the symbol to check
   1528  *  ident = the name of the expected UDA
   1529  */
   1530 bool isCoreUda(Dsymbol sym, Identifier ident)
   1531 {
   1532     if (sym.ident != ident || !sym.parent)
   1533         return false;
   1534 
   1535     auto _module = sym.parent.isModule();
   1536     return _module && _module.isCoreModule(Id.attribute);
   1537 }
   1538 
   1539 /**
   1540  * Iterates the UDAs attached to the given symbol.
   1541  *
   1542  * Params:
   1543  *  sym = the symbol to get the UDAs from
   1544  *  sc = scope to use for semantic analysis of UDAs
   1545  *  dg = called once for each UDA
   1546  *
   1547  * Returns:
   1548  *  If `dg` returns `!= 0`, stops the iteration and returns that value.
   1549  *  Otherwise, returns 0.
   1550  */
   1551 int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
   1552 {
   1553     if (!sym.userAttribDecl)
   1554         return 0;
   1555 
   1556     auto udas = sym.userAttribDecl.getAttributes();
   1557     arrayExpressionSemantic(udas, sc, true);
   1558 
   1559     return udas.each!((uda) {
   1560         if (!uda.isTupleExp())
   1561             return 0;
   1562 
   1563         auto exps = uda.isTupleExp().exps;
   1564 
   1565         return exps.each!((e) {
   1566             assert(e);
   1567 
   1568             if (auto result = dg(e))
   1569                 return result;
   1570 
   1571             return 0;
   1572         });
   1573     });
   1574 }
   1575 
   1576 /**
   1577  * Iterates the UDAs attached to the given symbol, without performing semantic
   1578  * analysis.
   1579  *
   1580  * Use this function instead of `foreachUda` if semantic analysis of `sym` is
   1581  * still in progress.
   1582  *
   1583  * Params:
   1584  *  sym = the symbol to get the UDAs from
   1585  *  dg = called once for each UDA
   1586  *
   1587  * Returns:
   1588  *  If `dg` returns `!= 0`, stops the iteration and returns that value.
   1589  *  Otherwise, returns 0.
   1590  */
   1591 int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
   1592 {
   1593     if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
   1594         return 0;
   1595 
   1596     foreach (exp; *sym.userAttribDecl.atts)
   1597     {
   1598         if (auto result = dg(exp))
   1599             return result;
   1600     }
   1601 
   1602     return 0;
   1603 }
   1604