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