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.errors;
37 import dmd.expression;
38 import dmd.expressionsem;
39 import dmd.func;
40 import dmd.globals;
41 import dmd.hdrgen : visibilityToBuffer;
42 import dmd.id;
43 import dmd.identifier;
44 import dmd.location;
45 import dmd.mtype;
46 import dmd.objc; // for objc.addSymbols
47 import dmd.common.outbuffer;
48 import dmd.root.array; // for each
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) @safe
61     {
62         this.decl = decl;
63     }
64 
65     extern (D) this(const ref Loc loc, Dsymbols* decl) @safe
66     {
67         super(loc, null);
68         this.decl = decl;
69     }
70 
71     extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe
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) @safe
232     {
233         super(decl);
234         this.stc = stc;
235     }
236 
237     extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl) @safe
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) @safe
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) @safe
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) @safe
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) @safe
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) @safe
528     {
529         super(loc, ident, decl);
530     }
531 
532     extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl) @safe
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) @safe
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) @safe
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             // https://issues.dlang.org/show_bug.cgi?id=17441
657             // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if
658             // each package's .isModule() properites are equal.
659             //
660             // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
661             // This breaks package declarations of the package in question if they are declared in
662             // the same package.d file, which _do_ have a module associated with them, and hence a non-null
663             // isModule()
664             if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
665             {
666                 Package pkg = m.parent ? m.parent.isPackage() : null;
667                 if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
668                     .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true));
669             }
670         }
671         return AttribDeclaration.addMember(sc, sds);
672     }
673 
674     override const(char)* kind() const
675     {
676         return "visibility attribute";
677     }
678 
679     override const(char)* toPrettyChars(bool)
680     {
681         assert(visibility.kind > Visibility.Kind.undefined);
682         OutBuffer buf;
683         visibilityToBuffer(buf, visibility);
684         return buf.extractChars();
685     }
686 
687     override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
688     {
689         return this;
690     }
691 
692     override void accept(Visitor v)
693     {
694         v.visit(this);
695     }
696 }
697 
698 /***********************************************************
699  * Alignment attribute for aggregates, members and variables.
700  *
701  * `align(<ealign>) <decl...>` or
702  * `align <decl...>` if `ealign` is null
703  */
704 extern (C++) final class AlignDeclaration : AttribDeclaration
705 {
706     Expressions* exps;                              /// Expression(s) yielding the desired alignment,
707                                                     /// the largest value wins
708     /// the actual alignment is Unknown until it's either set to the value of `ealign`
709     /// or the default if `ealign` is null ( / an error ocurred)
710     structalign_t salign;
711 
712 
713     extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
714     {
715         super(loc, null, decl);
716         if (exp)
717         {
718             exps = new Expressions();
719             exps.push(exp);
720         }
721     }
722 
723     extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl) @safe
724     {
725         super(loc, null, decl);
726         this.exps = exps;
727     }
728 
729     extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl) @safe
730     {
731         super(loc, null, decl);
732         this.salign = salign;
733     }
734 
735     override AlignDeclaration syntaxCopy(Dsymbol s)
736     {
737         assert(!s);
738         return new AlignDeclaration(loc,
739             Expression.arraySyntaxCopy(exps),
740             Dsymbol.arraySyntaxCopy(decl));
741     }
742 
743     override Scope* newScope(Scope* sc)
744     {
745         return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
746     }
747 
748     override void accept(Visitor v)
749     {
750         v.visit(this);
751     }
752 }
753 
754 /***********************************************************
755  * An anonymous struct/union (defined by `isunion`).
756  */
757 extern (C++) final class AnonDeclaration : AttribDeclaration
758 {
759     bool isunion;           /// whether it's a union
760     int sem;                /// 1 if successful semantic()
761     uint anonoffset;        /// offset of anonymous struct
762     uint anonstructsize;    /// size of anonymous struct
763     uint anonalignsize;     /// size of anonymous struct for alignment purposes
764 
765     extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) @safe
766     {
767         super(loc, null, decl);
768         this.isunion = isunion;
769     }
770 
771     override AnonDeclaration syntaxCopy(Dsymbol s)
772     {
773         assert(!s);
774         return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
775     }
776 
777     override void setScope(Scope* sc)
778     {
779         if (decl)
780             Dsymbol.setScope(sc);
781         return AttribDeclaration.setScope(sc);
782     }
783 
784     override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
785     {
786         //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
787         if (decl)
788         {
789             /* This works by treating an AnonDeclaration as an aggregate 'member',
790              * so in order to place that member we need to compute the member's
791              * size and alignment.
792              */
793             size_t fieldstart = ad.fields.length;
794 
795             /* Hackishly hijack ad's structsize and alignsize fields
796              * for use in our fake anon aggregate member.
797              */
798             uint savestructsize = ad.structsize;
799             uint savealignsize = ad.alignsize;
800             ad.structsize = 0;
801             ad.alignsize = 0;
802 
803             FieldState fs;
804             decl.foreachDsymbol( (s)
805             {
806                 s.setFieldOffset(ad, fs, this.isunion);
807                 if (this.isunion)
808                     fs.offset = 0;
809             });
810 
811             /* https://issues.dlang.org/show_bug.cgi?id=13613
812              * If the fields in this.members had been already
813              * added in ad.fields, just update *poffset for the subsequent
814              * field offset calculation.
815              */
816             if (fieldstart == ad.fields.length)
817             {
818                 ad.structsize = savestructsize;
819                 ad.alignsize = savealignsize;
820                 fieldState.offset = ad.structsize;
821                 return;
822             }
823 
824             anonstructsize = ad.structsize;
825             anonalignsize = ad.alignsize;
826             ad.structsize = savestructsize;
827             ad.alignsize = savealignsize;
828 
829             // 0 sized structs are set to 1 byte
830             if (anonstructsize == 0)
831             {
832                 anonstructsize = 1;
833                 anonalignsize = 1;
834             }
835 
836             assert(_scope);
837             auto alignment = _scope.alignment();
838 
839             /* Given the anon 'member's size and alignment,
840              * go ahead and place it.
841              */
842             anonoffset = placeField(
843                 fieldState.offset,
844                 anonstructsize, anonalignsize, alignment,
845                 ad.structsize, ad.alignsize,
846                 isunion);
847 
848             // Add to the anon fields the base offset of this anonymous aggregate
849             //printf("anon fields, anonoffset = %d\n", anonoffset);
850             foreach (const i; fieldstart .. ad.fields.length)
851             {
852                 VarDeclaration v = ad.fields[i];
853                 //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
854                 v.offset += anonoffset;
855             }
856         }
857     }
858 
859     override const(char)* kind() const
860     {
861         return (isunion ? "anonymous union" : "anonymous struct");
862     }
863 
864     override inout(AnonDeclaration) isAnonDeclaration() inout
865     {
866         return this;
867     }
868 
869     override void accept(Visitor v)
870     {
871         v.visit(this);
872     }
873 }
874 
875 /***********************************************************
876  * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
877  * but not PragmaStatement's like `pragma(msg, "hello");`.
878  *
879  * pragma(<ident>, <args>)
880  */
881 extern (C++) final class PragmaDeclaration : AttribDeclaration
882 {
883     Expressions* args;      /// parameters of this pragma
884 
885     extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) @safe
886     {
887         super(loc, ident, decl);
888         this.args = args;
889     }
890 
891     override PragmaDeclaration syntaxCopy(Dsymbol s)
892     {
893         //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
894         assert(!s);
895         return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
896     }
897 
898     override Scope* newScope(Scope* sc)
899     {
900         if (ident == Id.Pinline)
901         {
902             // We keep track of this pragma inside scopes,
903             // then it's evaluated on demand in function semantic
904             return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
905         }
906         return sc;
907     }
908 
909     override const(char)* kind() const
910     {
911         return "pragma";
912     }
913 
914     override void accept(Visitor v)
915     {
916         v.visit(this);
917     }
918 }
919 
920 /***********************************************************
921  * A conditional compilation declaration, used for `version`
922  * / `debug` and specialized for `static if`.
923  *
924  * <condition> { <decl...> } else { <elsedecl> }
925  */
926 extern (C++) class ConditionalDeclaration : AttribDeclaration
927 {
928     Condition condition;    /// condition deciding whether decl or elsedecl applies
929     Dsymbols* elsedecl;     /// array of Dsymbol's for else block
930 
931     extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
932     {
933         super(loc, null, decl);
934         //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
935         this.condition = condition;
936         this.elsedecl = elsedecl;
937     }
938 
939     override ConditionalDeclaration syntaxCopy(Dsymbol s)
940     {
941         assert(!s);
942         return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
943     }
944 
945     override final bool oneMember(Dsymbol* ps, Identifier ident)
946     {
947         //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
948         if (condition.inc != Include.notComputed)
949         {
950             Dsymbols* d = condition.include(null) ? decl : elsedecl;
951             return Dsymbol.oneMembers(d, ps, ident);
952         }
953         else
954         {
955             bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null);
956             *ps = null;
957             return res;
958         }
959     }
960 
961     // Decide if 'then' or 'else' code should be included
962     override Dsymbols* include(Scope* sc)
963     {
964         //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
965 
966         if (errors)
967             return null;
968 
969         assert(condition);
970         return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
971     }
972 
973     override final void addComment(const(char)* comment)
974     {
975         /* Because addComment is called by the parser, if we called
976          * include() it would define a version before it was used.
977          * But it's no problem to drill down to both decl and elsedecl,
978          * so that's the workaround.
979          */
980         if (comment)
981         {
982             decl    .foreachDsymbol( s => s.addComment(comment) );
983             elsedecl.foreachDsymbol( s => s.addComment(comment) );
984         }
985     }
986 
987     override void setScope(Scope* sc)
988     {
989         include(sc).foreachDsymbol( s => s.setScope(sc) );
990     }
991 
992     override void accept(Visitor v)
993     {
994         v.visit(this);
995     }
996 }
997 
998 /***********************************************************
999  * `<scopesym> {
1000  *      static if (<condition>) { <decl> } else { <elsedecl> }
1001  * }`
1002  */
1003 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
1004 {
1005     ScopeDsymbol scopesym;          /// enclosing symbol (e.g. module) where symbols will be inserted
1006     private bool addisdone = false; /// true if members have been added to scope
1007     private bool onStack = false;   /// true if a call to `include` is currently active
1008 
1009     extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
1010     {
1011         super(loc, condition, decl, elsedecl);
1012         //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
1013     }
1014 
1015     override StaticIfDeclaration syntaxCopy(Dsymbol s)
1016     {
1017         assert(!s);
1018         return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
1019     }
1020 
1021     /****************************************
1022      * Different from other AttribDeclaration subclasses, include() call requires
1023      * the completion of addMember and setScope phases.
1024      */
1025     override Dsymbols* include(Scope* sc)
1026     {
1027         //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
1028 
1029         if (errors || onStack)
1030             return null;
1031         onStack = true;
1032         scope(exit) onStack = false;
1033 
1034         if (sc && condition.inc == Include.notComputed)
1035         {
1036             assert(scopesym); // addMember is already done
1037             assert(_scope); // setScope is already done
1038             Dsymbols* d = ConditionalDeclaration.include(_scope);
1039             if (d && !addisdone)
1040             {
1041                 // Add members lazily.
1042                 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1043 
1044                 // Set the member scopes lazily.
1045                 d.foreachDsymbol( s => s.setScope(_scope) );
1046 
1047                 addisdone = true;
1048             }
1049             return d;
1050         }
1051         else
1052         {
1053             return ConditionalDeclaration.include(sc);
1054         }
1055     }
1056 
1057     override void addMember(Scope* sc, ScopeDsymbol sds)
1058     {
1059         //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
1060         /* This is deferred until the condition evaluated later (by the include() call),
1061          * so that expressions in the condition can refer to declarations
1062          * in the same scope, such as:
1063          *
1064          * template Foo(int i)
1065          * {
1066          *     const int j = i + 1;
1067          *     static if (j == 3)
1068          *         const int k;
1069          * }
1070          */
1071         this.scopesym = sds;
1072     }
1073 
1074     override void setScope(Scope* sc)
1075     {
1076         // do not evaluate condition before semantic pass
1077         // But do set the scope, in case we need it for forward referencing
1078         Dsymbol.setScope(sc);
1079     }
1080 
1081     override void importAll(Scope* sc)
1082     {
1083         // do not evaluate condition before semantic pass
1084     }
1085 
1086     override const(char)* kind() const
1087     {
1088         return "static if";
1089     }
1090 
1091     override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
1092     {
1093         return this;
1094     }
1095 
1096     override void accept(Visitor v)
1097     {
1098         v.visit(this);
1099     }
1100 }
1101 
1102 /***********************************************************
1103  * Static foreach at declaration scope, like:
1104  *     static foreach (i; [0, 1, 2]){ }
1105  */
1106 
1107 extern (C++) final class StaticForeachDeclaration : AttribDeclaration
1108 {
1109     StaticForeach sfe; /// contains `static foreach` expansion logic
1110 
1111     ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
1112 
1113     /++
1114      `include` can be called multiple times, but a `static foreach`
1115      should be expanded at most once.  Achieved by caching the result
1116      of the first call.  We need both `cached` and `cache`, because
1117      `null` is a valid value for `cache`.
1118      +/
1119     bool onStack = false;
1120     bool cached = false;
1121     Dsymbols* cache = null;
1122 
1123     extern (D) this(StaticForeach sfe, Dsymbols* decl) @safe
1124     {
1125         super(sfe.loc, null, decl);
1126         this.sfe = sfe;
1127     }
1128 
1129     override StaticForeachDeclaration syntaxCopy(Dsymbol s)
1130     {
1131         assert(!s);
1132         return new StaticForeachDeclaration(
1133             sfe.syntaxCopy(),
1134             Dsymbol.arraySyntaxCopy(decl));
1135     }
1136 
1137     override bool oneMember(Dsymbol* ps, Identifier ident)
1138     {
1139         // Required to support IFTI on a template that contains a
1140         // `static foreach` declaration.  `super.oneMember` calls
1141         // include with a `null` scope.  As `static foreach` requires
1142         // the scope for expansion, `oneMember` can only return a
1143         // precise result once `static foreach` has been expanded.
1144         if (cached)
1145         {
1146             return super.oneMember(ps, ident);
1147         }
1148         *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
1149         return false;
1150     }
1151 
1152     override Dsymbols* include(Scope* sc)
1153     {
1154         if (errors || onStack)
1155             return null;
1156         if (cached)
1157         {
1158             assert(!onStack);
1159             return cache;
1160         }
1161         onStack = true;
1162         scope(exit) onStack = false;
1163 
1164         if (_scope)
1165         {
1166             sfe.prepare(_scope); // lower static foreach aggregate
1167         }
1168         if (!sfe.ready())
1169         {
1170             return null; // TODO: ok?
1171         }
1172 
1173         // expand static foreach
1174         import dmd.statementsem: makeTupleForeach;
1175         Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
1176         if (d) // process generated declarations
1177         {
1178             // Add members lazily.
1179             d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1180 
1181             // Set the member scopes lazily.
1182             d.foreachDsymbol( s => s.setScope(_scope) );
1183         }
1184         cached = true;
1185         cache = d;
1186         return d;
1187     }
1188 
1189     override void addMember(Scope* sc, ScopeDsymbol sds)
1190     {
1191         // used only for caching the enclosing symbol
1192         this.scopesym = sds;
1193     }
1194 
1195     override void addComment(const(char)* comment)
1196     {
1197         // do nothing
1198         // change this to give semantics to documentation comments on static foreach declarations
1199     }
1200 
1201     override void setScope(Scope* sc)
1202     {
1203         // do not evaluate condition before semantic pass
1204         // But do set the scope, in case we need it for forward referencing
1205         Dsymbol.setScope(sc);
1206     }
1207 
1208     override void importAll(Scope* sc)
1209     {
1210         // do not evaluate aggregate before semantic pass
1211     }
1212 
1213     override const(char)* kind() const
1214     {
1215         return "static foreach";
1216     }
1217 
1218     override void accept(Visitor v)
1219     {
1220         v.visit(this);
1221     }
1222 }
1223 
1224 /***********************************************************
1225  * Collection of declarations that stores foreach index variables in a
1226  * local symbol table.  Other symbols declared within are forwarded to
1227  * another scope, like:
1228  *
1229  *      static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
1230  *      { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
1231  *          mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
1232  *      }
1233  *
1234  *      static foreach (i; 0.. 10)
1235  *      {
1236  *          pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
1237  *      }
1238  *
1239  *      static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
1240  *
1241  * A StaticForeachDeclaration generates one
1242  * ForwardingAttribDeclaration for each expansion of its body.  The
1243  * AST of the ForwardingAttribDeclaration contains both the `static
1244  * foreach` variables and the respective copy of the `static foreach`
1245  * body.  The functionality is achieved by using a
1246  * ForwardingScopeDsymbol as the parent symbol for the generated
1247  * declarations.
1248  */
1249 
1250 extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
1251 {
1252     ForwardingScopeDsymbol sym = null;
1253 
1254     this(Dsymbols* decl) @safe
1255     {
1256         super(decl);
1257         sym = new ForwardingScopeDsymbol();
1258         sym.symtab = new DsymbolTable();
1259     }
1260 
1261     /**************************************
1262      * Use the ForwardingScopeDsymbol as the parent symbol for members.
1263      */
1264     override Scope* newScope(Scope* sc)
1265     {
1266         return sc.push(sym);
1267     }
1268 
1269     /***************************************
1270      * Lazily initializes the scope to forward to.
1271      */
1272     override void addMember(Scope* sc, ScopeDsymbol sds)
1273     {
1274         sym.parent = sds;
1275         return super.addMember(sc, sym);
1276     }
1277 
1278     override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
1279     {
1280         return this;
1281     }
1282 
1283     override void accept(Visitor v)
1284     {
1285         v.visit(this);
1286     }
1287 }
1288 
1289 
1290 /***********************************************************
1291  * Mixin declarations, like:
1292  *      mixin("int x");
1293  * https://dlang.org/spec/module.html#mixin-declaration
1294  */
1295 // Note: was CompileDeclaration
1296 extern (C++) final class MixinDeclaration : AttribDeclaration
1297 {
1298     Expressions* exps;
1299     ScopeDsymbol scopesym;
1300     bool compiled;
1301 
1302     extern (D) this(const ref Loc loc, Expressions* exps) @safe
1303     {
1304         super(loc, null, null);
1305         //printf("MixinDeclaration(loc = %d)\n", loc.linnum);
1306         this.exps = exps;
1307     }
1308 
1309     override MixinDeclaration syntaxCopy(Dsymbol s)
1310     {
1311         //printf("MixinDeclaration::syntaxCopy('%s')\n", toChars());
1312         return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
1313     }
1314 
1315     override void addMember(Scope* sc, ScopeDsymbol sds)
1316     {
1317         //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
1318         this.scopesym = sds;
1319     }
1320 
1321     override void setScope(Scope* sc)
1322     {
1323         Dsymbol.setScope(sc);
1324     }
1325 
1326     override const(char)* kind() const
1327     {
1328         return "mixin";
1329     }
1330 
1331     override inout(MixinDeclaration) isMixinDeclaration() inout
1332     {
1333         return this;
1334     }
1335 
1336     override void accept(Visitor v)
1337     {
1338         v.visit(this);
1339     }
1340 }
1341 
1342 /***********************************************************
1343  * User defined attributes look like:
1344  *      @foo(args, ...)
1345  *      @(args, ...)
1346  */
1347 extern (C++) final class UserAttributeDeclaration : AttribDeclaration
1348 {
1349     Expressions* atts;
1350 
1351     extern (D) this(Expressions* atts, Dsymbols* decl) @safe
1352     {
1353         super(decl);
1354         this.atts = atts;
1355     }
1356 
1357     override UserAttributeDeclaration syntaxCopy(Dsymbol s)
1358     {
1359         //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
1360         assert(!s);
1361         return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
1362     }
1363 
1364     override Scope* newScope(Scope* sc)
1365     {
1366         Scope* sc2 = sc;
1367         if (atts && atts.length)
1368         {
1369             // create new one for changes
1370             sc2 = sc.copy();
1371             sc2.userAttribDecl = this;
1372         }
1373         return sc2;
1374     }
1375 
1376     override void setScope(Scope* sc)
1377     {
1378         //printf("UserAttributeDeclaration::setScope() %p\n", this);
1379         if (decl)
1380             Dsymbol.setScope(sc); // for forward reference of UDAs
1381         return AttribDeclaration.setScope(sc);
1382     }
1383 
1384     extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
1385     {
1386         Expressions* udas;
1387         if (!udas1 || udas1.length == 0)
1388             udas = udas2;
1389         else if (!udas2 || udas2.length == 0)
1390             udas = udas1;
1391         else
1392         {
1393             /* Create a new tuple that combines them
1394              * (do not append to left operand, as this is a copy-on-write operation)
1395              */
1396             udas = new Expressions(2);
1397             (*udas)[0] = new TupleExp(Loc.initial, udas1);
1398             (*udas)[1] = new TupleExp(Loc.initial, udas2);
1399         }
1400         return udas;
1401     }
1402 
1403     Expressions* getAttributes()
1404     {
1405         if (auto sc = _scope)
1406         {
1407             _scope = null;
1408             arrayExpressionSemantic(atts.peekSlice(), sc);
1409         }
1410         auto exps = new Expressions();
1411         if (userAttribDecl && userAttribDecl !is this)
1412             exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
1413         if (atts && atts.length)
1414             exps.push(new TupleExp(Loc.initial, atts));
1415         return exps;
1416     }
1417 
1418     override const(char)* kind() const
1419     {
1420         return "UserAttribute";
1421     }
1422 
1423     override void accept(Visitor v)
1424     {
1425         v.visit(this);
1426     }
1427 
1428     /**
1429      * Check if the provided expression references `core.attribute.gnuAbiTag`
1430      *
1431      * This should be called after semantic has been run on the expression.
1432      * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
1433      *
1434      * Params:
1435      *   e = Expression to check (usually from `UserAttributeDeclaration.atts`)
1436      *
1437      * Returns:
1438      *   `true` if the expression references the compiler-recognized `gnuAbiTag`
1439      */
1440     static bool isGNUABITag(Expression e)
1441     {
1442         if (global.params.cplusplus < CppStdRevision.cpp11)
1443             return false;
1444 
1445         auto ts = e.type ? e.type.isTypeStruct() : null;
1446         if (!ts)
1447             return false;
1448         if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
1449             return false;
1450         // Can only be defined in druntime
1451         Module m = ts.sym.parent.isModule();
1452         if (!m || !m.isCoreModule(Id.attribute))
1453             return false;
1454         return true;
1455     }
1456 
1457     /**
1458      * Called from a symbol's semantic to check if `gnuAbiTag` UDA
1459      * can be applied to them
1460      *
1461      * Directly emits an error if the UDA doesn't work with this symbol
1462      *
1463      * Params:
1464      *   sym = symbol to check for `gnuAbiTag`
1465      *   linkage = Linkage of the symbol (Declaration.link or sc.link)
1466      */
1467     static void checkGNUABITag(Dsymbol sym, LINK linkage)
1468     {
1469         if (global.params.cplusplus < CppStdRevision.cpp11)
1470             return;
1471 
1472         foreachUdaNoSemantic(sym, (exp) {
1473             if (isGNUABITag(exp))
1474             {
1475                 if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
1476                 {
1477                     .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
1478                     sym.errors = true;
1479                 }
1480                 else if (linkage != LINK.cpp)
1481                 {
1482                     .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
1483                     sym.errors = true;
1484                 }
1485                 // Only one `@gnuAbiTag` is allowed by semantic2
1486                 return 1; // break
1487             }
1488             return 0; // continue
1489         });
1490     }
1491 }
1492 
1493 /**
1494  * Returns `true` if the given symbol is a symbol declared in
1495  * `core.attribute` and has the given identifier.
1496  *
1497  * This is used to determine if a symbol is a UDA declared in
1498  * `core.attribute`.
1499  *
1500  * Params:
1501  *  sym = the symbol to check
1502  *  ident = the name of the expected UDA
1503  */
1504 bool isCoreUda(Dsymbol sym, Identifier ident)
1505 {
1506     if (sym.ident != ident || !sym.parent)
1507         return false;
1508 
1509     auto _module = sym.parent.isModule();
1510     return _module && _module.isCoreModule(Id.attribute);
1511 }
1512 
1513 /**
1514  * Iterates the UDAs attached to the given symbol.
1515  *
1516  * Params:
1517  *  sym = the symbol to get the UDAs from
1518  *  sc = scope to use for semantic analysis of UDAs
1519  *  dg = called once for each UDA
1520  *
1521  * Returns:
1522  *  If `dg` returns `!= 0`, stops the iteration and returns that value.
1523  *  Otherwise, returns 0.
1524  */
1525 int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
1526 {
1527     if (!sym.userAttribDecl)
1528         return 0;
1529 
1530     auto udas = sym.userAttribDecl.getAttributes();
1531     arrayExpressionSemantic(udas.peekSlice(), sc, true);
1532 
1533     return udas.each!((uda) {
1534         if (!uda.isTupleExp())
1535             return 0;
1536 
1537         auto exps = uda.isTupleExp().exps;
1538 
1539         return exps.each!((e) {
1540             assert(e);
1541 
1542             if (auto result = dg(e))
1543                 return result;
1544 
1545             return 0;
1546         });
1547     });
1548 }
1549 
1550 /**
1551  * Iterates the UDAs attached to the given symbol, without performing semantic
1552  * analysis.
1553  *
1554  * Use this function instead of `foreachUda` if semantic analysis of `sym` is
1555  * still in progress.
1556  *
1557  * Params:
1558  *  sym = the symbol to get the UDAs from
1559  *  dg = called once for each UDA
1560  *
1561  * Returns:
1562  *  If `dg` returns `!= 0`, stops the iteration and returns that value.
1563  *  Otherwise, returns 0.
1564  */
1565 int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
1566 {
1567     if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
1568         return 0;
1569 
1570     foreach (exp; *sym.userAttribDecl.atts)
1571     {
1572         if (auto result = dg(exp))
1573             return result;
1574     }
1575 
1576     return 0;
1577 }