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