d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688
[official-gcc.git] / gcc / d / dmd / attrib.d
blobd7d3eca6f8da0859ccdfe020d2f91bd3eecf0551
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-2024 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
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;
36 import dmd.errors;
37 import dmd.expression;
38 import dmd.expressionsem;
39 import dmd.func;
40 import dmd.globals;
41 import dmd.hdrgen : visibilityToBuffer;
42 import dmd.id;
43 import dmd.identifier;
44 import dmd.location;
45 import dmd.mtype;
46 import dmd.objc; // for objc.addSymbols
47 import dmd.common.outbuffer;
48 import dmd.root.array; // for each
49 import dmd.visitor;
51 /***********************************************************
52 * Abstract attribute applied to Dsymbol's used as a common
53 * ancestor for storage classes (StorageClassDeclaration),
54 * linkage (LinkageDeclaration) and others.
56 extern (C++) abstract class AttribDeclaration : Dsymbol
58 Dsymbols* decl; /// Dsymbol's affected by this AttribDeclaration
60 extern (D) this(Dsymbols* decl) @safe
62 this.decl = decl;
65 extern (D) this(const ref Loc loc, Dsymbols* decl) @safe
67 super(loc, null);
68 this.decl = decl;
71 extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe
73 super(loc, ident);
74 this.decl = decl;
77 Dsymbols* include(Scope* sc)
79 if (errors)
80 return null;
82 return decl;
85 /****************************************
86 * Create a new scope if one or more given attributes
87 * are different from the sc's.
88 * If the returned scope != sc, the caller should pop
89 * the scope after it used.
91 extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
92 CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
93 AlignDeclaration aligndecl, PragmaDeclaration inlining)
95 Scope* sc2 = sc;
96 if (stc != sc.stc ||
97 linkage != sc.linkage ||
98 cppmangle != sc.cppmangle ||
99 explicitVisibility != sc.explicitVisibility ||
100 visibility != sc.visibility ||
101 aligndecl !is sc.aligndecl ||
102 inlining != sc.inlining)
104 // create new one for changes
105 sc2 = sc.copy();
106 sc2.stc = stc;
107 sc2.linkage = linkage;
108 sc2.cppmangle = cppmangle;
109 sc2.visibility = visibility;
110 sc2.explicitVisibility = explicitVisibility;
111 sc2.aligndecl = aligndecl;
112 sc2.inlining = inlining;
114 return sc2;
117 /****************************************
118 * A hook point to supply scope for members.
119 * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
121 Scope* newScope(Scope* sc)
123 return sc;
126 override void addComment(const(char)* comment)
128 //printf("AttribDeclaration::addComment %s\n", comment);
129 if (comment)
131 include(null).foreachDsymbol( s => s.addComment(comment) );
135 override const(char)* kind() const
137 return "attribute";
140 override bool oneMember(out Dsymbol ps, Identifier ident)
142 Dsymbols* d = include(null);
143 return Dsymbol.oneMembers(d, ps, ident);
146 override final bool hasPointers()
148 return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
151 override final bool hasStaticCtorOrDtor()
153 return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
156 override final void checkCtorConstInit()
158 include(null).foreachDsymbol( s => s.checkCtorConstInit() );
161 /****************************************
163 override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
165 objc.addSymbols(this, classes, categories);
168 override inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
170 return this;
173 override void accept(Visitor v)
175 v.visit(this);
179 /***********************************************************
180 * Storage classes applied to Dsymbols, e.g. `const int i;`
182 * <stc> <decl...>
184 extern (C++) class StorageClassDeclaration : AttribDeclaration
186 StorageClass stc;
188 extern (D) this(StorageClass stc, Dsymbols* decl) @safe
190 super(decl);
191 this.stc = stc;
194 extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl) @safe
196 super(loc, decl);
197 this.stc = stc;
200 override StorageClassDeclaration syntaxCopy(Dsymbol s)
202 assert(!s);
203 return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
206 override Scope* newScope(Scope* sc)
208 StorageClass scstc = sc.stc;
209 /* These sets of storage classes are mutually exclusive,
210 * so choose the innermost or most recent one.
212 if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
213 scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
214 if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
215 scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
216 if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
217 scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
218 if (stc & (STC.gshared | STC.shared_))
219 scstc &= ~(STC.gshared | STC.shared_);
220 if (stc & (STC.safe | STC.trusted | STC.system))
221 scstc &= ~(STC.safe | STC.trusted | STC.system);
222 scstc |= stc;
223 //printf("scstc = x%llx\n", scstc);
224 return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
225 sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
228 override final bool oneMember(out Dsymbol ps, Identifier ident)
230 bool t = Dsymbol.oneMembers(decl, ps, ident);
231 if (t && ps)
233 /* This is to deal with the following case:
234 * struct Tick {
235 * template to(T) { const T to() { ... } }
237 * For eponymous function templates, the 'const' needs to get attached to 'to'
238 * before the semantic analysis of 'to', so that template overloading based on the
239 * 'this' pointer can be successful.
241 FuncDeclaration fd = ps.isFuncDeclaration();
242 if (fd)
244 /* Use storage_class2 instead of storage_class otherwise when we do .di generation
245 * we'll wind up with 'const const' rather than 'const'.
247 /* Don't think we need to worry about mutually exclusive storage classes here
249 fd.storage_class2 |= stc;
252 return t;
255 override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
257 return this;
260 override void accept(Visitor v)
262 v.visit(this);
266 /***********************************************************
267 * Deprecation with an additional message applied to Dsymbols,
268 * e.g. `deprecated("Superseeded by foo") int bar;`.
269 * (Note that `deprecated int bar;` is currently represented as a
270 * StorageClassDeclaration with STC.deprecated_)
272 * `deprecated(<msg>) <decl...>`
274 extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
276 Expression msg; /// deprecation message
277 const(char)* msgstr; /// cached string representation of msg
279 extern (D) this(Expression msg, Dsymbols* decl) @safe
281 super(STC.deprecated_, decl);
282 this.msg = msg;
285 override DeprecatedDeclaration syntaxCopy(Dsymbol s)
287 assert(!s);
288 return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
292 * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
294 * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
295 * in any function overriding `newScope`), then set the `Scope`'s depdecl.
297 * Returns:
298 * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
300 override Scope* newScope(Scope* sc)
302 auto scx = super.newScope(sc);
303 // The enclosing scope is deprecated as well
304 if (scx == sc)
305 scx = sc.push();
306 scx.depdecl = this;
307 return scx;
310 override void accept(Visitor v)
312 v.visit(this);
316 /***********************************************************
317 * Linkage attribute applied to Dsymbols, e.g.
318 * `extern(C) void foo()`.
320 * `extern(<linkage>) <decl...>`
322 extern (C++) final class LinkDeclaration : AttribDeclaration
324 LINK linkage; /// either explicitly set or `default_`
326 extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl) @safe
328 super(loc, null, decl);
329 //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
330 this.linkage = linkage;
333 static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl) @safe
335 return new LinkDeclaration(loc, p, decl);
338 override LinkDeclaration syntaxCopy(Dsymbol s)
340 assert(!s);
341 return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
344 override Scope* newScope(Scope* sc)
346 return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
347 sc.aligndecl, sc.inlining);
350 override const(char)* toChars() const
352 return toString().ptr;
355 extern(D) override const(char)[] toString() const
357 return "extern ()";
360 override void accept(Visitor v)
362 v.visit(this);
366 /***********************************************************
367 * Attribute declaring whether an external aggregate should be mangled as
368 * a struct or class in C++, e.g. `extern(C++, struct) class C { ... }`.
369 * This is required for correct name mangling on MSVC targets,
370 * see cppmanglewin.d for details.
372 * `extern(C++, <cppmangle>) <decl...>`
374 extern (C++) final class CPPMangleDeclaration : AttribDeclaration
376 CPPMANGLE cppmangle;
378 extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl) @safe
380 super(loc, null, decl);
381 //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
382 this.cppmangle = cppmangle;
385 override CPPMangleDeclaration syntaxCopy(Dsymbol s)
387 assert(!s);
388 return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
391 override Scope* newScope(Scope* sc)
393 return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
394 sc.aligndecl, sc.inlining);
397 override const(char)* toChars() const
399 return toString().ptr;
402 extern(D) override const(char)[] toString() const
404 return "extern ()";
407 override void accept(Visitor v)
409 v.visit(this);
414 * A node to represent an `extern(C++)` namespace attribute
416 * There are two ways to declarate a symbol as member of a namespace:
417 * `Nspace` and `CPPNamespaceDeclaration`.
418 * The former creates a scope for the symbol, and inject them in the
419 * parent scope at the same time.
420 * The later, this class, has no semantic implications and is only
421 * used for mangling.
422 * Additionally, this class allows one to use reserved identifiers
423 * (D keywords) in the namespace.
425 * A `CPPNamespaceDeclaration` can be created from an `Identifier`
426 * (already resolved) or from an `Expression`, which is CTFE-ed
427 * and can be either a `TupleExp`, in which can additional
428 * `CPPNamespaceDeclaration` nodes are created, or a `StringExp`.
430 * Note that this class, like `Nspace`, matches only one identifier
431 * part of a namespace. For the namespace `"foo::bar"`,
432 * the will be a `CPPNamespaceDeclaration` with its `ident`
433 * set to `"bar"`, and its `namespace` field pointing to another
434 * `CPPNamespaceDeclaration` with its `ident` set to `"foo"`.
436 extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
438 /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
439 Expression exp;
441 extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe
443 super(loc, ident, decl);
446 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl) @safe
448 super(loc, null, decl);
449 this.exp = exp;
452 extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
453 CPPNamespaceDeclaration parent) @safe
455 super(loc, ident, decl);
456 this.exp = exp;
457 this.cppnamespace = parent;
460 override CPPNamespaceDeclaration syntaxCopy(Dsymbol s)
462 assert(!s);
463 return new CPPNamespaceDeclaration(
464 this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
468 * Returns:
469 * A copy of the parent scope, with `this` as `namespace` and C++ linkage
471 override Scope* newScope(Scope* sc)
473 auto scx = sc.copy();
474 scx.linkage = LINK.cpp;
475 scx.namespace = this;
476 return scx;
479 override const(char)* toChars() const
481 return toString().ptr;
484 extern(D) override const(char)[] toString() const
486 return "extern (C++, `namespace`)";
489 override void accept(Visitor v)
491 v.visit(this);
494 override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
497 /***********************************************************
498 * Visibility declaration for Dsymbols, e.g. `public int i;`
500 * `<visibility> <decl...>` or
501 * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
503 extern (C++) final class VisibilityDeclaration : AttribDeclaration
505 Visibility visibility; /// the visibility
506 Identifier[] pkg_identifiers; /// identifiers for `package(foo.bar)` or null
509 * Params:
510 * loc = source location of attribute token
511 * visibility = visibility attribute data
512 * decl = declarations which are affected by this visibility attribute
514 extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl) @safe
516 super(loc, null, decl);
517 this.visibility = visibility;
518 //printf("decl = %p\n", decl);
522 * Params:
523 * loc = source location of attribute token
524 * pkg_identifiers = list of identifiers for a qualified package name
525 * decl = declarations which are affected by this visibility attribute
527 extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
529 super(loc, null, decl);
530 this.visibility.kind = Visibility.Kind.package_;
531 this.pkg_identifiers = pkg_identifiers;
532 if (pkg_identifiers.length > 0)
534 Dsymbol tmp;
535 Package.resolve(pkg_identifiers, &tmp, null);
536 visibility.pkg = tmp ? tmp.isPackage() : null;
540 override VisibilityDeclaration syntaxCopy(Dsymbol s)
542 assert(!s);
544 if (visibility.kind == Visibility.Kind.package_)
545 return new VisibilityDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
546 else
547 return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
550 override Scope* newScope(Scope* sc)
552 if (pkg_identifiers)
553 dsymbolSemantic(this, sc);
554 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
557 override const(char)* kind() const
559 return "visibility attribute";
562 override const(char)* toPrettyChars(bool)
564 assert(visibility.kind > Visibility.Kind.undefined);
565 OutBuffer buf;
566 visibilityToBuffer(buf, visibility);
567 return buf.extractChars();
570 override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
572 return this;
575 override void accept(Visitor v)
577 v.visit(this);
581 /***********************************************************
582 * Alignment attribute for aggregates, members and variables.
584 * `align(<ealign>) <decl...>` or
585 * `align <decl...>` if `ealign` is null
587 extern (C++) final class AlignDeclaration : AttribDeclaration
589 Expressions* exps; /// Expression(s) yielding the desired alignment,
590 /// the largest value wins
591 /// the actual alignment is Unknown until it's either set to the value of `ealign`
592 /// or the default if `ealign` is null ( / an error ocurred)
593 structalign_t salign;
596 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
598 super(loc, null, decl);
599 if (exp)
601 exps = new Expressions();
602 exps.push(exp);
606 extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl) @safe
608 super(loc, null, decl);
609 this.exps = exps;
612 extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl) @safe
614 super(loc, null, decl);
615 this.salign = salign;
618 override AlignDeclaration syntaxCopy(Dsymbol s)
620 assert(!s);
621 return new AlignDeclaration(loc,
622 Expression.arraySyntaxCopy(exps),
623 Dsymbol.arraySyntaxCopy(decl));
626 override Scope* newScope(Scope* sc)
628 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
631 override void accept(Visitor v)
633 v.visit(this);
637 /***********************************************************
638 * An anonymous struct/union (defined by `isunion`).
640 extern (C++) final class AnonDeclaration : AttribDeclaration
642 bool isunion; /// whether it's a union
643 int sem; /// 1 if successful semantic()
644 uint anonoffset; /// offset of anonymous struct
645 uint anonstructsize; /// size of anonymous struct
646 uint anonalignsize; /// size of anonymous struct for alignment purposes
648 extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) @safe
650 super(loc, null, decl);
651 this.isunion = isunion;
654 override AnonDeclaration syntaxCopy(Dsymbol s)
656 assert(!s);
657 return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
660 override const(char)* kind() const
662 return (isunion ? "anonymous union" : "anonymous struct");
665 override inout(AnonDeclaration) isAnonDeclaration() inout
667 return this;
670 override void accept(Visitor v)
672 v.visit(this);
676 /***********************************************************
677 * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
678 * but not PragmaStatement's like `pragma(msg, "hello");`.
680 * pragma(<ident>, <args>)
682 extern (C++) final class PragmaDeclaration : AttribDeclaration
684 Expressions* args; /// parameters of this pragma
686 extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) @safe
688 super(loc, ident, decl);
689 this.args = args;
692 override PragmaDeclaration syntaxCopy(Dsymbol s)
694 //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
695 assert(!s);
696 return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
699 override Scope* newScope(Scope* sc)
701 if (ident == Id.Pinline)
703 // We keep track of this pragma inside scopes,
704 // then it's evaluated on demand in function semantic
705 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
707 return sc;
710 override const(char)* kind() const
712 return "pragma";
715 override void accept(Visitor v)
717 v.visit(this);
721 /***********************************************************
722 * A conditional compilation declaration, used for `version`
723 * / `debug` and specialized for `static if`.
725 * <condition> { <decl...> } else { <elsedecl> }
727 extern (C++) class ConditionalDeclaration : AttribDeclaration
729 Condition condition; /// condition deciding whether decl or elsedecl applies
730 Dsymbols* elsedecl; /// array of Dsymbol's for else block
732 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
734 super(loc, null, decl);
735 //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
736 this.condition = condition;
737 this.elsedecl = elsedecl;
740 override ConditionalDeclaration syntaxCopy(Dsymbol s)
742 assert(!s);
743 return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
746 override final bool oneMember(out Dsymbol ps, Identifier ident)
748 //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
749 if (condition.inc != Include.notComputed)
751 Dsymbols* d = condition.include(null) ? decl : elsedecl;
752 return Dsymbol.oneMembers(d, ps, ident);
754 else
756 bool res = (Dsymbol.oneMembers(decl, ps, ident) && ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && ps is null);
757 ps = null;
758 return res;
762 // Decide if 'then' or 'else' code should be included
763 override Dsymbols* include(Scope* sc)
765 //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
767 if (errors)
768 return null;
770 assert(condition);
771 return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
774 override final void addComment(const(char)* comment)
776 /* Because addComment is called by the parser, if we called
777 * include() it would define a version before it was used.
778 * But it's no problem to drill down to both decl and elsedecl,
779 * so that's the workaround.
781 if (comment)
783 decl .foreachDsymbol( s => s.addComment(comment) );
784 elsedecl.foreachDsymbol( s => s.addComment(comment) );
788 override void accept(Visitor v)
790 v.visit(this);
794 /***********************************************************
795 * `<scopesym> {
796 * static if (<condition>) { <decl> } else { <elsedecl> }
797 * }`
799 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
801 ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted
802 private bool addisdone = false; /// true if members have been added to scope
803 private bool onStack = false; /// true if a call to `include` is currently active
805 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
807 super(loc, condition, decl, elsedecl);
808 //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
811 override StaticIfDeclaration syntaxCopy(Dsymbol s)
813 assert(!s);
814 return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
817 /****************************************
818 * Different from other AttribDeclaration subclasses, include() call requires
819 * the completion of addMember and setScope phases.
821 override Dsymbols* include(Scope* sc)
823 //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
825 if (errors || onStack)
826 return null;
827 onStack = true;
828 scope(exit) onStack = false;
830 if (sc && condition.inc == Include.notComputed)
832 assert(scopesym); // addMember is already done
833 assert(_scope); // setScope is already done
834 Dsymbols* d = ConditionalDeclaration.include(_scope);
835 if (d && !addisdone)
837 // Add members lazily.
838 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
840 // Set the member scopes lazily.
841 d.foreachDsymbol( s => s.setScope(_scope) );
843 addisdone = true;
845 return d;
847 else
849 return ConditionalDeclaration.include(sc);
853 override const(char)* kind() const
855 return "static if";
858 override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
860 return this;
863 override void accept(Visitor v)
865 v.visit(this);
869 /***********************************************************
870 * Static foreach at declaration scope, like:
871 * static foreach (i; [0, 1, 2]){ }
874 extern (C++) final class StaticForeachDeclaration : AttribDeclaration
876 StaticForeach sfe; /// contains `static foreach` expansion logic
878 ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
881 `include` can be called multiple times, but a `static foreach`
882 should be expanded at most once. Achieved by caching the result
883 of the first call. We need both `cached` and `cache`, because
884 `null` is a valid value for `cache`.
886 bool onStack = false;
887 bool cached = false;
888 Dsymbols* cache = null;
890 extern (D) this(StaticForeach sfe, Dsymbols* decl) @safe
892 super(sfe.loc, null, decl);
893 this.sfe = sfe;
896 override StaticForeachDeclaration syntaxCopy(Dsymbol s)
898 assert(!s);
899 return new StaticForeachDeclaration(
900 sfe.syntaxCopy(),
901 Dsymbol.arraySyntaxCopy(decl));
904 override bool oneMember(out Dsymbol ps, Identifier ident)
906 // Required to support IFTI on a template that contains a
907 // `static foreach` declaration. `super.oneMember` calls
908 // include with a `null` scope. As `static foreach` requires
909 // the scope for expansion, `oneMember` can only return a
910 // precise result once `static foreach` has been expanded.
911 if (cached)
913 return super.oneMember(ps, ident);
915 ps = null; // a `static foreach` declaration may in general expand to multiple symbols
916 return false;
919 override Dsymbols* include(Scope* sc)
921 if (errors || onStack)
922 return null;
923 if (cached)
925 assert(!onStack);
926 return cache;
928 onStack = true;
929 scope(exit) onStack = false;
931 if (_scope)
933 sfe.prepare(_scope); // lower static foreach aggregate
935 if (!sfe.ready())
937 return null; // TODO: ok?
940 // expand static foreach
941 import dmd.statementsem: makeTupleForeach;
942 Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
943 if (d) // process generated declarations
945 // Add members lazily.
946 d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
948 // Set the member scopes lazily.
949 d.foreachDsymbol( s => s.setScope(_scope) );
951 cached = true;
952 cache = d;
953 return d;
956 override void addComment(const(char)* comment)
958 // do nothing
959 // change this to give semantics to documentation comments on static foreach declarations
962 override const(char)* kind() const
964 return "static foreach";
967 override void accept(Visitor v)
969 v.visit(this);
973 /***********************************************************
974 * Collection of declarations that stores foreach index variables in a
975 * local symbol table. Other symbols declared within are forwarded to
976 * another scope, like:
978 * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
979 * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
980 * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
983 * static foreach (i; 0.. 10)
985 * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
988 * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
990 * A StaticForeachDeclaration generates one
991 * ForwardingAttribDeclaration for each expansion of its body. The
992 * AST of the ForwardingAttribDeclaration contains both the `static
993 * foreach` variables and the respective copy of the `static foreach`
994 * body. The functionality is achieved by using a
995 * ForwardingScopeDsymbol as the parent symbol for the generated
996 * declarations.
999 extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
1001 ForwardingScopeDsymbol sym = null;
1003 this(Dsymbols* decl) @safe
1005 super(decl);
1006 sym = new ForwardingScopeDsymbol();
1007 sym.symtab = new DsymbolTable();
1010 /**************************************
1011 * Use the ForwardingScopeDsymbol as the parent symbol for members.
1013 override Scope* newScope(Scope* sc)
1015 return sc.push(sym);
1018 override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
1020 return this;
1023 override void accept(Visitor v)
1025 v.visit(this);
1030 /***********************************************************
1031 * Mixin declarations, like:
1032 * mixin("int x");
1033 * https://dlang.org/spec/module.html#mixin-declaration
1035 // Note: was CompileDeclaration
1036 extern (C++) final class MixinDeclaration : AttribDeclaration
1038 Expressions* exps;
1039 ScopeDsymbol scopesym;
1040 bool compiled;
1042 extern (D) this(const ref Loc loc, Expressions* exps) @safe
1044 super(loc, null, null);
1045 //printf("MixinDeclaration(loc = %d)\n", loc.linnum);
1046 this.exps = exps;
1049 override MixinDeclaration syntaxCopy(Dsymbol s)
1051 //printf("MixinDeclaration::syntaxCopy('%s')\n", toChars());
1052 return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
1055 override const(char)* kind() const
1057 return "mixin";
1060 override inout(MixinDeclaration) isMixinDeclaration() inout
1062 return this;
1065 override void accept(Visitor v)
1067 v.visit(this);
1071 /***********************************************************
1072 * User defined attributes look like:
1073 * @foo(args, ...)
1074 * @(args, ...)
1076 extern (C++) final class UserAttributeDeclaration : AttribDeclaration
1078 Expressions* atts;
1080 extern (D) this(Expressions* atts, Dsymbols* decl) @safe
1082 super(decl);
1083 this.atts = atts;
1086 override UserAttributeDeclaration syntaxCopy(Dsymbol s)
1088 //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
1089 assert(!s);
1090 return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
1093 override Scope* newScope(Scope* sc)
1095 Scope* sc2 = sc;
1096 if (atts && atts.length)
1098 // create new one for changes
1099 sc2 = sc.copy();
1100 sc2.userAttribDecl = this;
1102 return sc2;
1105 extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
1107 Expressions* udas;
1108 if (!udas1 || udas1.length == 0)
1109 udas = udas2;
1110 else if (!udas2 || udas2.length == 0)
1111 udas = udas1;
1112 else
1114 /* Create a new tuple that combines them
1115 * (do not append to left operand, as this is a copy-on-write operation)
1117 udas = new Expressions(2);
1118 (*udas)[0] = new TupleExp(Loc.initial, udas1);
1119 (*udas)[1] = new TupleExp(Loc.initial, udas2);
1121 return udas;
1124 Expressions* getAttributes()
1126 if (auto sc = _scope)
1128 _scope = null;
1129 arrayExpressionSemantic(atts.peekSlice(), sc);
1131 auto exps = new Expressions();
1132 if (userAttribDecl && userAttribDecl !is this)
1133 exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
1134 if (atts && atts.length)
1135 exps.push(new TupleExp(Loc.initial, atts));
1136 return exps;
1139 override const(char)* kind() const
1141 return "UserAttribute";
1144 override void accept(Visitor v)
1146 v.visit(this);
1150 * Check if the provided expression references `core.attribute.gnuAbiTag`
1152 * This should be called after semantic has been run on the expression.
1153 * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
1155 * Params:
1156 * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
1158 * Returns:
1159 * `true` if the expression references the compiler-recognized `gnuAbiTag`
1161 static bool isGNUABITag(Expression e)
1163 if (global.params.cplusplus < CppStdRevision.cpp11)
1164 return false;
1166 auto ts = e.type ? e.type.isTypeStruct() : null;
1167 if (!ts)
1168 return false;
1169 if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
1170 return false;
1171 // Can only be defined in druntime
1172 Module m = ts.sym.parent.isModule();
1173 if (!m || !m.isCoreModule(Id.attribute))
1174 return false;
1175 return true;
1179 * Called from a symbol's semantic to check if `gnuAbiTag` UDA
1180 * can be applied to them
1182 * Directly emits an error if the UDA doesn't work with this symbol
1184 * Params:
1185 * sym = symbol to check for `gnuAbiTag`
1186 * linkage = Linkage of the symbol (Declaration.link or sc.link)
1188 static void checkGNUABITag(Dsymbol sym, LINK linkage)
1190 if (global.params.cplusplus < CppStdRevision.cpp11)
1191 return;
1193 foreachUdaNoSemantic(sym, (exp) {
1194 if (isGNUABITag(exp))
1196 if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
1198 .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
1199 sym.errors = true;
1201 else if (linkage != LINK.cpp)
1203 .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
1204 sym.errors = true;
1206 // Only one `@gnuAbiTag` is allowed by semantic2
1207 return 1; // break
1209 return 0; // continue
1215 * Returns `true` if the given symbol is a symbol declared in
1216 * `core.attribute` and has the given identifier.
1218 * This is used to determine if a symbol is a UDA declared in
1219 * `core.attribute`.
1221 * Params:
1222 * sym = the symbol to check
1223 * ident = the name of the expected UDA
1225 bool isCoreUda(Dsymbol sym, Identifier ident)
1227 if (sym.ident != ident || !sym.parent)
1228 return false;
1230 auto _module = sym.parent.isModule();
1231 return _module && _module.isCoreModule(Id.attribute);
1235 * Iterates the UDAs attached to the given symbol.
1237 * Params:
1238 * sym = the symbol to get the UDAs from
1239 * sc = scope to use for semantic analysis of UDAs
1240 * dg = called once for each UDA
1242 * Returns:
1243 * If `dg` returns `!= 0`, stops the iteration and returns that value.
1244 * Otherwise, returns 0.
1246 int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
1248 if (!sym.userAttribDecl)
1249 return 0;
1251 auto udas = sym.userAttribDecl.getAttributes();
1252 arrayExpressionSemantic(udas.peekSlice(), sc, true);
1254 return udas.each!((uda) {
1255 if (!uda.isTupleExp())
1256 return 0;
1258 auto exps = uda.isTupleExp().exps;
1260 return exps.each!((e) {
1261 assert(e);
1263 if (auto result = dg(e))
1264 return result;
1266 return 0;
1272 * Iterates the UDAs attached to the given symbol, without performing semantic
1273 * analysis.
1275 * Use this function instead of `foreachUda` if semantic analysis of `sym` is
1276 * still in progress.
1278 * Params:
1279 * sym = the symbol to get the UDAs from
1280 * dg = called once for each UDA
1282 * Returns:
1283 * If `dg` returns `!= 0`, stops the iteration and returns that value.
1284 * Otherwise, returns 0.
1286 int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
1288 if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
1289 return 0;
1291 foreach (exp; *sym.userAttribDecl.atts)
1293 if (auto result = dg(exp))
1294 return result;
1297 return 0;
1302 * Returns: true if the given expression is an enum from `core.attribute` named `id`
1304 bool isEnumAttribute(Expression e, Identifier id)
1306 import dmd.attrib : isCoreUda;
1307 import dmd.id : Id;
1309 // Logic based on dmd.objc.Supported.declaredAsOptionalCount
1310 auto typeExp = e.isTypeExp;
1311 if (!typeExp)
1312 return false;
1314 auto typeEnum = typeExp.type.isTypeEnum();
1315 if (!typeEnum)
1316 return false;
1318 if (isCoreUda(typeEnum.sym, id))
1319 return true;
1321 return false;