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