d: Merge upstream dmd 568496d5b, druntime 178c44ff, phobos 574bf883b.
[official-gcc.git] / gcc / d / dmd / attrib.d
blob0bf40ef9a728d4cce3518269c3f58c49930a5ebc
1 /**
2 * Defines declarations of various attributes.
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`)
17 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
18 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
19 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
20 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
21 * Documentation: https://dlang.org/phobos/dmd_attrib.html
22 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
25 module dmd.attrib;
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.target; // for target.systemLinkage
47 import dmd.tokens;
48 import dmd.visitor;
50 /***********************************************************
51 * Abstract attribute applied to Dsymbol's used as a common
52 * ancestor for storage classes (StorageClassDeclaration),
53 * linkage (LinkageDeclaration) and others.
55 extern (C++) abstract class AttribDeclaration : Dsymbol
57 Dsymbols* decl; /// Dsymbol's affected by this AttribDeclaration
59 extern (D) this(Dsymbols* decl)
61 this.decl = decl;
64 extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
66 super(loc, ident);
67 this.decl = decl;
70 Dsymbols* include(Scope* sc)
72 if (errors)
73 return null;
75 return decl;
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.
84 extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
85 CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
86 AlignDeclaration aligndecl, PragmaDeclaration inlining)
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)
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;
107 return sc2;
110 /****************************************
111 * A hook point to supply scope for members.
112 * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
114 Scope* newScope(Scope* sc)
116 return sc;
119 override void addMember(Scope* sc, ScopeDsymbol sds)
121 Dsymbols* d = include(sc);
122 if (d)
124 Scope* sc2 = newScope(sc);
125 d.foreachDsymbol( s => s.addMember(sc2, sds) );
126 if (sc2 != sc)
127 sc2.pop();
131 override void setScope(Scope* sc)
133 Dsymbols* d = include(sc);
134 //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
135 if (d)
137 Scope* sc2 = newScope(sc);
138 d.foreachDsymbol( s => s.setScope(sc2) );
139 if (sc2 != sc)
140 sc2.pop();
144 override void importAll(Scope* sc)
146 Dsymbols* d = include(sc);
147 //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
148 if (d)
150 Scope* sc2 = newScope(sc);
151 d.foreachDsymbol( s => s.importAll(sc2) );
152 if (sc2 != sc)
153 sc2.pop();
157 override void addComment(const(char)* comment)
159 //printf("AttribDeclaration::addComment %s\n", comment);
160 if (comment)
162 include(null).foreachDsymbol( s => s.addComment(comment) );
166 override const(char)* kind() const
168 return "attribute";
171 override bool oneMember(Dsymbol* ps, Identifier ident)
173 Dsymbols* d = include(null);
174 return Dsymbol.oneMembers(d, ps, ident);
177 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
179 include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
182 override final bool hasPointers()
184 return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
187 override final bool hasStaticCtorOrDtor()
189 return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
192 override final void checkCtorConstInit()
194 include(null).foreachDsymbol( s => s.checkCtorConstInit() );
197 /****************************************
199 override final void addLocalClass(ClassDeclarations* aclasses)
201 include(null).foreachDsymbol( s => s.addLocalClass(aclasses) );
204 override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
206 objc.addSymbols(this, classes, categories);
209 override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
211 return this;
214 override void accept(Visitor v)
216 v.visit(this);
220 /***********************************************************
221 * Storage classes applied to Dsymbols, e.g. `const int i;`
223 * <stc> <decl...>
225 extern (C++) class StorageClassDeclaration : AttribDeclaration
227 StorageClass stc;
229 extern (D) this(StorageClass stc, Dsymbols* decl)
231 super(decl);
232 this.stc = stc;
235 override StorageClassDeclaration syntaxCopy(Dsymbol s)
237 assert(!s);
238 return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
241 override Scope* newScope(Scope* sc)
243 StorageClass scstc = sc.stc;
244 /* These sets of storage classes are mutually exclusive,
245 * so choose the innermost or most recent one.
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.tls | STC.manifest | STC.gshared))
250 scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | 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_ | STC.tls))
254 scstc &= ~(STC.gshared | STC.shared_ | STC.tls);
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);
263 override final bool oneMember(Dsymbol* ps, Identifier ident)
265 bool t = Dsymbol.oneMembers(decl, ps, ident);
266 if (t && *ps)
268 /* This is to deal with the following case:
269 * struct Tick {
270 * template to(T) { const T to() { ... } }
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.
276 FuncDeclaration fd = (*ps).isFuncDeclaration();
277 if (fd)
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'.
282 /* Don't think we need to worry about mutually exclusive storage classes here
284 fd.storage_class2 |= stc;
287 return t;
290 override void addMember(Scope* sc, ScopeDsymbol sds)
292 Dsymbols* d = include(sc);
293 if (d)
295 Scope* sc2 = newScope(sc);
297 d.foreachDsymbol( (s)
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())
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?
306 sdecl.stc |= stc & STC.local;
309 s.addMember(sc2, sds);
312 if (sc2 != sc)
313 sc2.pop();
318 override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
320 return this;
323 override void accept(Visitor v)
325 v.visit(this);
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_)
335 * `deprecated(<msg>) <decl...>`
337 extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
339 Expression msg; /// deprecation message
340 const(char)* msgstr; /// cached string representation of msg
342 extern (D) this(Expression msg, Dsymbols* decl)
344 super(STC.deprecated_, decl);
345 this.msg = msg;
348 override DeprecatedDeclaration syntaxCopy(Dsymbol s)
350 assert(!s);
351 return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
355 * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
357 * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
358 * in any function overriding `newScope`), then set the `Scope`'s depdecl.
360 * Returns:
361 * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
363 override Scope* newScope(Scope* sc)
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;
373 override void setScope(Scope* sc)
375 //printf("DeprecatedDeclaration::setScope() %p\n", this);
376 if (decl)
377 Dsymbol.setScope(sc); // for forward reference
378 return AttribDeclaration.setScope(sc);
381 override void accept(Visitor v)
383 v.visit(this);
387 /***********************************************************
388 * Linkage attribute applied to Dsymbols, e.g.
389 * `extern(C) void foo()`.
391 * `extern(<linkage>) <decl...>`
393 extern (C++) final class LinkDeclaration : AttribDeclaration
395 LINK linkage; /// either explicitly set or `default_`
397 extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl)
399 super(loc, null, decl);
400 //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
401 this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
404 static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
406 return new LinkDeclaration(loc, p, decl);
409 override LinkDeclaration syntaxCopy(Dsymbol s)
411 assert(!s);
412 return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
415 override Scope* newScope(Scope* sc)
417 return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
418 sc.aligndecl, sc.inlining);
421 override const(char)* toChars() const
423 return toString().ptr;
426 extern(D) override const(char)[] toString() const
428 return "extern ()";
431 override void accept(Visitor v)
433 v.visit(this);
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.
443 * `extern(C++, <cppmangle>) <decl...>`
445 extern (C++) final class CPPMangleDeclaration : AttribDeclaration
447 CPPMANGLE cppmangle;
449 extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl)
451 super(loc, null, decl);
452 //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
453 this.cppmangle = cppmangle;
456 override CPPMangleDeclaration syntaxCopy(Dsymbol s)
458 assert(!s);
459 return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
462 override Scope* newScope(Scope* sc)
464 return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
465 sc.aligndecl, sc.inlining);
468 override void setScope(Scope* sc)
470 if (decl)
471 Dsymbol.setScope(sc); // for forward reference
472 return AttribDeclaration.setScope(sc);
475 override const(char)* toChars() const
477 return toString().ptr;
480 extern(D) override const(char)[] toString() const
482 return "extern ()";
485 override void accept(Visitor v)
487 v.visit(this);
492 * A node to represent an `extern(C++)` namespace attribute
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.
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`.
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"`.
514 extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
516 /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
517 Expression exp;
519 extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
521 super(loc, ident, decl);
524 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
526 super(loc, null, decl);
527 this.exp = exp;
530 extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
531 CPPNamespaceDeclaration parent)
533 super(loc, ident, decl);
534 this.exp = exp;
535 this.cppnamespace = parent;
538 override CPPNamespaceDeclaration syntaxCopy(Dsymbol s)
540 assert(!s);
541 return new CPPNamespaceDeclaration(
542 this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
546 * Returns:
547 * A copy of the parent scope, with `this` as `namespace` and C++ linkage
549 override Scope* newScope(Scope* sc)
551 auto scx = sc.copy();
552 scx.linkage = LINK.cpp;
553 scx.namespace = this;
554 return scx;
557 override const(char)* toChars() const
559 return toString().ptr;
562 extern(D) override const(char)[] toString() const
564 return "extern (C++, `namespace`)";
567 override void accept(Visitor v)
569 v.visit(this);
572 override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
575 /***********************************************************
576 * Visibility declaration for Dsymbols, e.g. `public int i;`
578 * `<visibility> <decl...>` or
579 * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
581 extern (C++) final class VisibilityDeclaration : AttribDeclaration
583 Visibility visibility; /// the visibility
584 Identifier[] pkg_identifiers; /// identifiers for `package(foo.bar)` or null
587 * Params:
588 * loc = source location of attribute token
589 * visibility = visibility attribute data
590 * decl = declarations which are affected by this visibility attribute
592 extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl)
594 super(loc, null, decl);
595 this.visibility = visibility;
596 //printf("decl = %p\n", decl);
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
605 extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
607 super(loc, null, decl);
608 this.visibility.kind = Visibility.Kind.package_;
609 this.pkg_identifiers = pkg_identifiers;
610 if (pkg_identifiers.length > 0)
612 Dsymbol tmp;
613 Package.resolve(pkg_identifiers, &tmp, null);
614 visibility.pkg = tmp ? tmp.isPackage() : null;
618 override VisibilityDeclaration syntaxCopy(Dsymbol s)
620 assert(!s);
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));
628 override Scope* newScope(Scope* sc)
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);
635 override void addMember(Scope* sc, ScopeDsymbol sds)
637 if (pkg_identifiers)
639 Dsymbol tmp;
640 Package.resolve(pkg_identifiers, &tmp, null);
641 visibility.pkg = tmp ? tmp.isPackage() : null;
642 pkg_identifiers = null;
644 if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
646 Module m = sc._module;
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.
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))
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));
662 return AttribDeclaration.addMember(sc, sds);
665 override const(char)* kind() const
667 return "visibility attribute";
670 override const(char)* toPrettyChars(bool)
672 assert(visibility.kind > Visibility.Kind.undefined);
673 OutBuffer buf;
674 visibilityToBuffer(&buf, visibility);
675 return buf.extractChars();
678 override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
680 return this;
683 override void accept(Visitor v)
685 v.visit(this);
689 /***********************************************************
690 * Alignment attribute for aggregates, members and variables.
692 * `align(<ealign>) <decl...>` or
693 * `align <decl...>` if `ealign` is null
695 extern (C++) final class AlignDeclaration : AttribDeclaration
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;
704 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
706 super(loc, null, decl);
707 if (exp)
709 exps = new Expressions();
710 exps.push(exp);
714 extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl)
716 super(loc, null, decl);
717 this.exps = exps;
720 extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl)
722 super(loc, null, decl);
723 this.salign = salign;
726 override AlignDeclaration syntaxCopy(Dsymbol s)
728 assert(!s);
729 return new AlignDeclaration(loc,
730 Expression.arraySyntaxCopy(exps),
731 Dsymbol.arraySyntaxCopy(decl));
734 override Scope* newScope(Scope* sc)
736 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
739 override void accept(Visitor v)
741 v.visit(this);
745 /***********************************************************
746 * An anonymous struct/union (defined by `isunion`).
748 extern (C++) final class AnonDeclaration : AttribDeclaration
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
756 extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl)
758 super(loc, null, decl);
759 this.isunion = isunion;
762 override AnonDeclaration syntaxCopy(Dsymbol s)
764 assert(!s);
765 return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
768 override void setScope(Scope* sc)
770 if (decl)
771 Dsymbol.setScope(sc);
772 return AttribDeclaration.setScope(sc);
775 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
777 //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
778 if (decl)
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.
784 size_t fieldstart = ad.fields.dim;
786 /* Hackishly hijack ad's structsize and alignsize fields
787 * for use in our fake anon aggregate member.
789 uint savestructsize = ad.structsize;
790 uint savealignsize = ad.alignsize;
791 ad.structsize = 0;
792 ad.alignsize = 0;
794 FieldState fs;
795 decl.foreachDsymbol( (s)
797 s.setFieldOffset(ad, fs, this.isunion);
798 if (this.isunion)
799 fs.offset = 0;
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.
807 if (fieldstart == ad.fields.dim)
809 ad.structsize = savestructsize;
810 ad.alignsize = savealignsize;
811 fieldState.offset = ad.structsize;
812 return;
815 anonstructsize = ad.structsize;
816 anonalignsize = ad.alignsize;
817 ad.structsize = savestructsize;
818 ad.alignsize = savealignsize;
820 // 0 sized structs are set to 1 byte
821 if (anonstructsize == 0)
823 anonstructsize = 1;
824 anonalignsize = 1;
827 assert(_scope);
828 auto alignment = _scope.alignment();
830 /* Given the anon 'member's size and alignment,
831 * go ahead and place it.
833 anonoffset = AggregateDeclaration.placeField(
834 &fieldState.offset,
835 anonstructsize, anonalignsize, alignment,
836 &ad.structsize, &ad.alignsize,
837 isunion);
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)
843 VarDeclaration v = ad.fields[i];
844 //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
845 v.offset += anonoffset;
850 override const(char)* kind() const
852 return (isunion ? "anonymous union" : "anonymous struct");
855 override inout(AnonDeclaration) isAnonDeclaration() inout
857 return this;
860 override void accept(Visitor v)
862 v.visit(this);
866 /***********************************************************
867 * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
868 * but not PragmaStatement's like `pragma(msg, "hello");`.
870 * pragma(<ident>, <args>)
872 extern (C++) final class PragmaDeclaration : AttribDeclaration
874 Expressions* args; /// parameters of this pragma
876 extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl)
878 super(loc, ident, decl);
879 this.args = args;
882 override PragmaDeclaration syntaxCopy(Dsymbol s)
884 //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
885 assert(!s);
886 return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
889 override Scope* newScope(Scope* sc)
891 if (ident == Id.Pinline)
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);
897 if (ident == Id.printf || ident == Id.scanf)
899 auto sc2 = sc.push();
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;
907 return sc2;
909 return sc;
912 PINLINE evalPragmaInline(Scope* sc)
914 if (!args || args.dim == 0)
915 return PINLINE.default_;
917 Expression e = (*args)[0];
918 if (!e.type)
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;
932 if (e.isBool(true))
933 return PINLINE.always;
934 else if (e.isBool(false))
935 return PINLINE.never;
936 else
937 return PINLINE.default_;
940 override const(char)* kind() const
942 return "pragma";
945 override void accept(Visitor v)
947 v.visit(this);
951 /***********************************************************
952 * A conditional compilation declaration, used for `version`
953 * / `debug` and specialized for `static if`.
955 * <condition> { <decl...> } else { <elsedecl> }
957 extern (C++) class ConditionalDeclaration : AttribDeclaration
959 Condition condition; /// condition deciding whether decl or elsedecl applies
960 Dsymbols* elsedecl; /// array of Dsymbol's for else block
962 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
964 super(loc, null, decl);
965 //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
966 this.condition = condition;
967 this.elsedecl = elsedecl;
970 override ConditionalDeclaration syntaxCopy(Dsymbol s)
972 assert(!s);
973 return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
976 override final bool oneMember(Dsymbol* ps, Identifier ident)
978 //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
979 if (condition.inc != Include.notComputed)
981 Dsymbols* d = condition.include(null) ? decl : elsedecl;
982 return Dsymbol.oneMembers(d, ps, ident);
984 else
986 bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null);
987 *ps = null;
988 return res;
992 // Decide if 'then' or 'else' code should be included
993 override Dsymbols* include(Scope* sc)
995 //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
997 if (errors)
998 return null;
1000 assert(condition);
1001 return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
1004 override final void addComment(const(char)* comment)
1006 /* Because addComment is called by the parser, if we called
1007 * include() it would define a version before it was used.
1008 * But it's no problem to drill down to both decl and elsedecl,
1009 * so that's the workaround.
1011 if (comment)
1013 decl .foreachDsymbol( s => s.addComment(comment) );
1014 elsedecl.foreachDsymbol( s => s.addComment(comment) );
1018 override void setScope(Scope* sc)
1020 include(sc).foreachDsymbol( s => s.setScope(sc) );
1023 override void accept(Visitor v)
1025 v.visit(this);
1029 /***********************************************************
1030 * `<scopesym> {
1031 * static if (<condition>) { <decl> } else { <elsedecl> }
1032 * }`
1034 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
1036 ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted
1037 private bool addisdone = false; /// true if members have been added to scope
1038 private bool onStack = false; /// true if a call to `include` is currently active
1040 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
1042 super(loc, condition, decl, elsedecl);
1043 //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
1046 override StaticIfDeclaration syntaxCopy(Dsymbol s)
1048 assert(!s);
1049 return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
1052 /****************************************
1053 * Different from other AttribDeclaration subclasses, include() call requires
1054 * the completion of addMember and setScope phases.
1056 override Dsymbols* include(Scope* sc)
1058 //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
1060 if (errors || onStack)
1061 return null;
1062 onStack = true;
1063 scope(exit) onStack = false;
1065 if (sc && condition.inc == Include.notComputed)
1067 assert(scopesym); // addMember is already done
1068 assert(_scope); // setScope is already done
1069 Dsymbols* d = ConditionalDeclaration.include(_scope);
1070 if (d && !addisdone)
1072 // Add members lazily.
1073 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1075 // Set the member scopes lazily.
1076 d.foreachDsymbol( s => s.setScope(_scope) );
1078 addisdone = true;
1080 return d;
1082 else
1084 return ConditionalDeclaration.include(sc);
1088 override void addMember(Scope* sc, ScopeDsymbol sds)
1090 //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
1091 /* This is deferred until the condition evaluated later (by the include() call),
1092 * so that expressions in the condition can refer to declarations
1093 * in the same scope, such as:
1095 * template Foo(int i)
1097 * const int j = i + 1;
1098 * static if (j == 3)
1099 * const int k;
1102 this.scopesym = sds;
1105 override void setScope(Scope* sc)
1107 // do not evaluate condition before semantic pass
1108 // But do set the scope, in case we need it for forward referencing
1109 Dsymbol.setScope(sc);
1112 override void importAll(Scope* sc)
1114 // do not evaluate condition before semantic pass
1117 override const(char)* kind() const
1119 return "static if";
1122 override void accept(Visitor v)
1124 v.visit(this);
1128 /***********************************************************
1129 * Static foreach at declaration scope, like:
1130 * static foreach (i; [0, 1, 2]){ }
1133 extern (C++) final class StaticForeachDeclaration : AttribDeclaration
1135 StaticForeach sfe; /// contains `static foreach` expansion logic
1137 ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
1140 `include` can be called multiple times, but a `static foreach`
1141 should be expanded at most once. Achieved by caching the result
1142 of the first call. We need both `cached` and `cache`, because
1143 `null` is a valid value for `cache`.
1145 bool onStack = false;
1146 bool cached = false;
1147 Dsymbols* cache = null;
1149 extern (D) this(StaticForeach sfe, Dsymbols* decl)
1151 super(sfe.loc, null, decl);
1152 this.sfe = sfe;
1155 override StaticForeachDeclaration syntaxCopy(Dsymbol s)
1157 assert(!s);
1158 return new StaticForeachDeclaration(
1159 sfe.syntaxCopy(),
1160 Dsymbol.arraySyntaxCopy(decl));
1163 override bool oneMember(Dsymbol* ps, Identifier ident)
1165 // Required to support IFTI on a template that contains a
1166 // `static foreach` declaration. `super.oneMember` calls
1167 // include with a `null` scope. As `static foreach` requires
1168 // the scope for expansion, `oneMember` can only return a
1169 // precise result once `static foreach` has been expanded.
1170 if (cached)
1172 return super.oneMember(ps, ident);
1174 *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
1175 return false;
1178 override Dsymbols* include(Scope* sc)
1180 if (errors || onStack)
1181 return null;
1182 if (cached)
1184 assert(!onStack);
1185 return cache;
1187 onStack = true;
1188 scope(exit) onStack = false;
1190 if (_scope)
1192 sfe.prepare(_scope); // lower static foreach aggregate
1194 if (!sfe.ready())
1196 return null; // TODO: ok?
1199 // expand static foreach
1200 import dmd.statementsem: makeTupleForeach;
1201 Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl;
1202 if (d) // process generated declarations
1204 // Add members lazily.
1205 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1207 // Set the member scopes lazily.
1208 d.foreachDsymbol( s => s.setScope(_scope) );
1210 cached = true;
1211 cache = d;
1212 return d;
1215 override void addMember(Scope* sc, ScopeDsymbol sds)
1217 // used only for caching the enclosing symbol
1218 this.scopesym = sds;
1221 override void addComment(const(char)* comment)
1223 // do nothing
1224 // change this to give semantics to documentation comments on static foreach declarations
1227 override void setScope(Scope* sc)
1229 // do not evaluate condition before semantic pass
1230 // But do set the scope, in case we need it for forward referencing
1231 Dsymbol.setScope(sc);
1234 override void importAll(Scope* sc)
1236 // do not evaluate aggregate before semantic pass
1239 override const(char)* kind() const
1241 return "static foreach";
1244 override void accept(Visitor v)
1246 v.visit(this);
1250 /***********************************************************
1251 * Collection of declarations that stores foreach index variables in a
1252 * local symbol table. Other symbols declared within are forwarded to
1253 * another scope, like:
1255 * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
1256 * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
1257 * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
1260 * static foreach (i; 0.. 10)
1262 * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
1265 * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
1267 * A StaticForeachDeclaration generates one
1268 * ForwardingAttribDeclaration for each expansion of its body. The
1269 * AST of the ForwardingAttribDeclaration contains both the `static
1270 * foreach` variables and the respective copy of the `static foreach`
1271 * body. The functionality is achieved by using a
1272 * ForwardingScopeDsymbol as the parent symbol for the generated
1273 * declarations.
1276 extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
1278 ForwardingScopeDsymbol sym = null;
1280 this(Dsymbols* decl)
1282 super(decl);
1283 sym = new ForwardingScopeDsymbol(null);
1284 sym.symtab = new DsymbolTable();
1287 /**************************************
1288 * Use the ForwardingScopeDsymbol as the parent symbol for members.
1290 override Scope* newScope(Scope* sc)
1292 return sc.push(sym);
1295 /***************************************
1296 * Lazily initializes the scope to forward to.
1298 override void addMember(Scope* sc, ScopeDsymbol sds)
1300 parent = sym.parent = sym.forward = sds;
1301 return super.addMember(sc, sym);
1304 override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
1306 return this;
1309 override void accept(Visitor v)
1311 v.visit(this);
1316 /***********************************************************
1317 * Mixin declarations, like:
1318 * mixin("int x");
1319 * https://dlang.org/spec/module.html#mixin-declaration
1321 extern (C++) final class CompileDeclaration : AttribDeclaration
1323 Expressions* exps;
1324 ScopeDsymbol scopesym;
1325 bool compiled;
1327 extern (D) this(const ref Loc loc, Expressions* exps)
1329 super(loc, null, null);
1330 //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
1331 this.exps = exps;
1334 override CompileDeclaration syntaxCopy(Dsymbol s)
1336 //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
1337 return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
1340 override void addMember(Scope* sc, ScopeDsymbol sds)
1342 //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
1343 this.scopesym = sds;
1346 override void setScope(Scope* sc)
1348 Dsymbol.setScope(sc);
1351 override const(char)* kind() const
1353 return "mixin";
1356 override inout(CompileDeclaration) isCompileDeclaration() inout
1358 return this;
1361 override void accept(Visitor v)
1363 v.visit(this);
1367 /***********************************************************
1368 * User defined attributes look like:
1369 * @foo(args, ...)
1370 * @(args, ...)
1372 extern (C++) final class UserAttributeDeclaration : AttribDeclaration
1374 Expressions* atts;
1376 extern (D) this(Expressions* atts, Dsymbols* decl)
1378 super(decl);
1379 this.atts = atts;
1382 override UserAttributeDeclaration syntaxCopy(Dsymbol s)
1384 //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
1385 assert(!s);
1386 return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
1389 override Scope* newScope(Scope* sc)
1391 Scope* sc2 = sc;
1392 if (atts && atts.dim)
1394 // create new one for changes
1395 sc2 = sc.copy();
1396 sc2.userAttribDecl = this;
1398 return sc2;
1401 override void setScope(Scope* sc)
1403 //printf("UserAttributeDeclaration::setScope() %p\n", this);
1404 if (decl)
1405 Dsymbol.setScope(sc); // for forward reference of UDAs
1406 return AttribDeclaration.setScope(sc);
1409 extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
1411 Expressions* udas;
1412 if (!udas1 || udas1.dim == 0)
1413 udas = udas2;
1414 else if (!udas2 || udas2.dim == 0)
1415 udas = udas1;
1416 else
1418 /* Create a new tuple that combines them
1419 * (do not append to left operand, as this is a copy-on-write operation)
1421 udas = new Expressions(2);
1422 (*udas)[0] = new TupleExp(Loc.initial, udas1);
1423 (*udas)[1] = new TupleExp(Loc.initial, udas2);
1425 return udas;
1428 Expressions* getAttributes()
1430 if (auto sc = _scope)
1432 _scope = null;
1433 arrayExpressionSemantic(atts, sc);
1435 auto exps = new Expressions();
1436 if (userAttribDecl && userAttribDecl !is this)
1437 exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
1438 if (atts && atts.dim)
1439 exps.push(new TupleExp(Loc.initial, atts));
1440 return exps;
1443 override const(char)* kind() const
1445 return "UserAttribute";
1448 override void accept(Visitor v)
1450 v.visit(this);
1454 * Check if the provided expression references `core.attribute.gnuAbiTag`
1456 * This should be called after semantic has been run on the expression.
1457 * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
1459 * Params:
1460 * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
1462 * Returns:
1463 * `true` if the expression references the compiler-recognized `gnuAbiTag`
1465 static bool isGNUABITag(Expression e)
1467 if (global.params.cplusplus < CppStdRevision.cpp11)
1468 return false;
1470 auto ts = e.type ? e.type.isTypeStruct() : null;
1471 if (!ts)
1472 return false;
1473 if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
1474 return false;
1475 // Can only be defined in druntime
1476 Module m = ts.sym.parent.isModule();
1477 if (!m || !m.isCoreModule(Id.attribute))
1478 return false;
1479 return true;
1483 * Called from a symbol's semantic to check if `gnuAbiTag` UDA
1484 * can be applied to them
1486 * Directly emits an error if the UDA doesn't work with this symbol
1488 * Params:
1489 * sym = symbol to check for `gnuAbiTag`
1490 * linkage = Linkage of the symbol (Declaration.link or sc.link)
1492 static void checkGNUABITag(Dsymbol sym, LINK linkage)
1494 if (global.params.cplusplus < CppStdRevision.cpp11)
1495 return;
1497 // Avoid `if` at the call site
1498 if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
1499 return;
1501 foreach (exp; *sym.userAttribDecl.atts)
1503 if (isGNUABITag(exp))
1505 if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
1507 exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
1508 sym.errors = true;
1510 else if (linkage != LINK.cpp)
1512 exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
1513 sym.errors = true;
1515 // Only one `@gnuAbiTag` is allowed by semantic2
1516 return;