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