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