2 * Defines declarations of various attributes.
4 * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
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
28 import dmd
.arraytypes
;
31 import dmd
.declaration
;
35 import dmd
.dsymbolsem
: dsymbolSemantic
;
36 import dmd
.expression
;
37 import dmd
.expressionsem
;
40 import dmd
.hdrgen
: visibilityToBuffer
;
42 import dmd
.identifier
;
44 import dmd
.objc
; // for objc.addSymbols
45 import dmd
.common
.outbuffer
;
46 import dmd
.target
; // for target.systemLinkage
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
)
64 extern (D
) this(const ref Loc loc
, Identifier ident
, Dsymbols
* decl
)
70 Dsymbols
* include(Scope
* sc
)
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
)
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
100 sc2
.linkage
= linkage
;
101 sc2
.cppmangle
= cppmangle
;
102 sc2
.visibility
= visibility
;
103 sc2
.explicitVisibility
= explicitVisibility
;
104 sc2
.aligndecl
= aligndecl
;
105 sc2
.inlining
= inlining
;
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
)
119 override void addMember(Scope
* sc
, ScopeDsymbol sds
)
121 Dsymbols
* d
= include(sc
);
124 Scope
* sc2
= newScope(sc
);
125 d
.foreachDsymbol( s
=> s
.addMember(sc2
, sds
) );
131 override void setScope(Scope
* sc
)
133 Dsymbols
* d
= include(sc
);
134 //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
137 Scope
* sc2
= newScope(sc
);
138 d
.foreachDsymbol( s
=> s
.setScope(sc2
) );
144 override void importAll(Scope
* sc
)
146 Dsymbols
* d
= include(sc
);
147 //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
150 Scope
* sc2
= newScope(sc
);
151 d
.foreachDsymbol( s
=> s
.importAll(sc2
) );
157 override void addComment(const(char)* comment
)
159 //printf("AttribDeclaration::addComment %s\n", comment);
162 include(null).foreachDsymbol( s
=> s
.addComment(comment
) );
166 override const(char)* kind() const
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
214 override void accept(Visitor v
)
220 /***********************************************************
221 * Storage classes applied to Dsymbols, e.g. `const int i;`
225 extern (C
++) class StorageClassDeclaration
: AttribDeclaration
229 extern (D
) this(StorageClass
stc, Dsymbols
* decl
)
235 override StorageClassDeclaration
syntaxCopy(Dsymbol 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
);
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
);
268 /* This is to deal with the following case:
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();
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;
290 override void addMember(Scope
* sc
, ScopeDsymbol sds
)
292 Dsymbols
* d
= include(sc
);
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
);
318 override inout(StorageClassDeclaration
) isStorageClassDeclaration() inout
323 override void accept(Visitor v
)
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
);
348 override DeprecatedDeclaration
syntaxCopy(Dsymbol 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.
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
373 override void setScope(Scope
* sc
)
375 //printf("DeprecatedDeclaration::setScope() %p\n", this);
377 Dsymbol
.setScope(sc
); // for forward reference
378 return AttribDeclaration
.setScope(sc
);
381 override void accept(Visitor v
)
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
)
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
431 override void accept(Visitor v
)
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
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
)
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
)
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
485 override void accept(Visitor v
)
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
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`
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
);
530 extern (D
) this(const ref Loc loc
, Identifier ident
, Expression exp
, Dsymbols
* decl
,
531 CPPNamespaceDeclaration parent
)
533 super(loc
, ident
, decl
);
535 this.cppnamespace
= parent
;
538 override CPPNamespaceDeclaration
syntaxCopy(Dsymbol s
)
541 return new CPPNamespaceDeclaration(
542 this.loc
, this.ident
, this.exp
, Dsymbol
.arraySyntaxCopy(this.decl
), this.cppnamespace
);
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;
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
)
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
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);
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)
613 Package
.resolve(pkg_identifiers
, &tmp
, null);
614 visibility
.pkg
= tmp ? tmp
.isPackage() : null;
618 override VisibilityDeclaration
syntaxCopy(Dsymbol s
)
622 if (visibility
.kind
== Visibility
.Kind
.package_
)
623 return new VisibilityDeclaration(this.loc
, pkg_identifiers
, Dsymbol
.arraySyntaxCopy(decl
));
625 return new VisibilityDeclaration(this.loc
, visibility
, Dsymbol
.arraySyntaxCopy(decl
));
628 override Scope
* newScope(Scope
* sc
)
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
)
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
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
);
674 visibilityToBuffer(&buf
, visibility
);
675 return buf
.extractChars();
678 override inout(VisibilityDeclaration
) isVisibilityDeclaration() inout
683 override void accept(Visitor v
)
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
);
709 exps
= new Expressions();
714 extern (D
) this(const ref Loc loc
, Expressions
* exps
, Dsymbols
* decl
)
716 super(loc
, null, decl
);
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
)
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
)
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
)
765 return new AnonDeclaration(loc
, isunion
, Dsymbol
.arraySyntaxCopy(decl
));
768 override void setScope(Scope
* sc
)
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);
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
;
795 decl
.foreachDsymbol( (s
)
797 s
.setFieldOffset(ad
, fs
, this.isunion
);
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
;
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)
828 auto alignment
= _scope
.alignment();
830 /* Given the anon 'member's size and alignment,
831 * go ahead and place it.
833 anonoffset
= AggregateDeclaration
.placeField(
835 anonstructsize
, anonalignsize
, alignment
,
836 &ad
.structsize
, &ad
.alignsize
,
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
860 override void accept(Visitor v
)
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
);
882 override PragmaDeclaration
syntaxCopy(Dsymbol s
)
884 //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
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
;
905 sc2
.flags
= (sc2
.flags
& ~SCOPE
.printf
) | SCOPE
.scanf
;
912 PINLINE
evalPragmaInline(Scope
* sc
)
914 if (!args || args
.dim
== 0)
915 return PINLINE
.default_
;
917 Expression e
= (*args
)[0];
922 e
= e
.expressionSemantic(sc
);
923 e
= resolveProperties(sc
, e
);
925 e
= e
.ctfeInterpret();
928 error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args
)[0].toChars());
933 return PINLINE
.always
;
934 else if (e
.isBool(false))
935 return PINLINE
.never
;
937 return PINLINE
.default_
;
940 override const(char)* kind() const
945 override void accept(Visitor v
)
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
)
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
);
986 bool res
= (Dsymbol
.oneMembers(decl
, ps
, ident
) && *ps
is null && Dsymbol
.oneMembers(elsedecl
, ps
, ident
) && *ps
is null);
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);
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.
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
)
1029 /***********************************************************
1031 * static if (<condition>) { <decl> } else { <elsedecl> }
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
)
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
)
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
) );
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)
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
1122 override void accept(Visitor v
)
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
);
1155 override StaticForeachDeclaration
syntaxCopy(Dsymbol s
)
1158 return new StaticForeachDeclaration(
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.
1172 return super.oneMember(ps
, ident
);
1174 *ps
= null; // a `static foreach` declaration may in general expand to multiple symbols
1178 override Dsymbols
* include(Scope
* sc
)
1180 if (errors || onStack
)
1188 scope(exit
) onStack
= false;
1192 sfe
.prepare(_scope
); // lower static foreach aggregate
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
) );
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
)
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
)
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
1276 extern(C
++) final class ForwardingAttribDeclaration
: AttribDeclaration
1278 ForwardingScopeDsymbol sym
= null;
1280 this(Dsymbols
* 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
1309 override void accept(Visitor v
)
1316 /***********************************************************
1317 * Mixin declarations, like:
1319 * https://dlang.org/spec/module.html#mixin-declaration
1321 extern (C
++) final class CompileDeclaration
: AttribDeclaration
1324 ScopeDsymbol scopesym
;
1327 extern (D
) this(const ref Loc loc
, Expressions
* exps
)
1329 super(loc
, null, null);
1330 //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
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
1356 override inout(CompileDeclaration
) isCompileDeclaration() inout
1361 override void accept(Visitor v
)
1367 /***********************************************************
1368 * User defined attributes look like:
1372 extern (C
++) final class UserAttributeDeclaration
: AttribDeclaration
1376 extern (D
) this(Expressions
* atts
, Dsymbols
* decl
)
1382 override UserAttributeDeclaration
syntaxCopy(Dsymbol s
)
1384 //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
1386 return new UserAttributeDeclaration(Expression
.arraySyntaxCopy(this.atts
), Dsymbol
.arraySyntaxCopy(decl
));
1389 override Scope
* newScope(Scope
* sc
)
1392 if (atts
&& atts
.dim
)
1394 // create new one for changes
1396 sc2
.userAttribDecl
= this;
1401 override void setScope(Scope
* sc
)
1403 //printf("UserAttributeDeclaration::setScope() %p\n", this);
1405 Dsymbol
.setScope(sc
); // for forward reference of UDAs
1406 return AttribDeclaration
.setScope(sc
);
1409 extern (D
) static Expressions
* concat(Expressions
* udas1
, Expressions
* udas2
)
1412 if (!udas1 || udas1
.dim
== 0)
1414 else if (!udas2 || udas2
.dim
== 0)
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
);
1428 Expressions
* getAttributes()
1430 if (auto sc
= _scope
)
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
));
1443 override const(char)* kind() const
1445 return "UserAttribute";
1448 override void accept(Visitor v
)
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`).
1460 * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
1463 * `true` if the expression references the compiler-recognized `gnuAbiTag`
1465 static bool isGNUABITag(Expression e
)
1467 if (global
.params
.cplusplus
< CppStdRevision
.cpp11
)
1470 auto ts
= e
.type ? e
.type
.isTypeStruct() : null;
1473 if (ts
.sym
.ident
!= Id
.udaGNUAbiTag ||
!ts
.sym
.parent
)
1475 // Can only be defined in druntime
1476 Module m
= ts
.sym
.parent
.isModule();
1477 if (!m ||
!m
.isCoreModule(Id
.attribute
))
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
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
)
1497 // Avoid `if` at the call site
1498 if (sym
.userAttribDecl
is null || sym
.userAttribDecl
.atts
is null)
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());
1510 else if (linkage
!= LINK
.cpp
)
1512 exp
.error("`@%s` can only apply to C++ symbols", Id
.udaGNUAbiTag
.toChars());
1515 // Only one `@gnuAbiTag` is allowed by semantic2