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