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-2020 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 : arrayExpressionSemantic; 37 import dmd.func; 38 import dmd.globals; 39 import dmd.hdrgen : protectionToBuffer; 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, Prot protection, int explicitProtection, 85 AlignDeclaration aligndecl, PINLINE inlining) 86 { 87 Scope* sc2 = sc; 88 if (stc != sc.stc || 89 linkage != sc.linkage || 90 cppmangle != sc.cppmangle || 91 !protection.isSubsetOf(sc.protection) || 92 explicitProtection != sc.explicitProtection || 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.protection = protection; 102 sc2.explicitProtection = explicitProtection; 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 Dsymbol 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.protection, sc.explicitProtection, 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 Dsymbol 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(LINK linkage, Dsymbols* decl) 397 { 398 super(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(LINK p, Dsymbols* decl) 404 { 405 return new LinkDeclaration(p, decl); 406 } 407 408 override Dsymbol syntaxCopy(Dsymbol s) 409 { 410 assert(!s); 411 return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl)); 412 } 413 414 override Scope* newScope(Scope* sc) 415 { 416 return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, 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(CPPMANGLE cppmangle, Dsymbols* decl) 449 { 450 super(decl); 451 //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl); 452 this.cppmangle = cppmangle; 453 } 454 455 override Dsymbol syntaxCopy(Dsymbol s) 456 { 457 assert(!s); 458 return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl)); 459 } 460 461 override Scope* newScope(Scope* sc) 462 { 463 return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.protection, sc.explicitProtection, 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(Identifier ident, Dsymbols* decl) 519 { 520 super(decl); 521 this.ident = ident; 522 } 523 524 extern (D) this(Expression exp, Dsymbols* decl) 525 { 526 super(decl); 527 this.exp = exp; 528 } 529 530 extern (D) this(Identifier ident, Expression exp, Dsymbols* decl, 531 CPPNamespaceDeclaration parent) 532 { 533 super(decl); 534 this.ident = ident; 535 this.exp = exp; 536 this.cppnamespace = parent; 537 } 538 539 override Dsymbol syntaxCopy(Dsymbol s) 540 { 541 assert(!s); 542 return new CPPNamespaceDeclaration( 543 this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace); 544 } 545 546 /** 547 * Returns: 548 * A copy of the parent scope, with `this` as `namespace` and C++ linkage 549 */ 550 override Scope* newScope(Scope* sc) 551 { 552 auto scx = sc.copy(); 553 scx.linkage = LINK.cpp; 554 scx.namespace = this; 555 return scx; 556 } 557 558 override const(char)* toChars() const 559 { 560 return toString().ptr; 561 } 562 563 extern(D) override const(char)[] toString() const 564 { 565 return "extern (C++, `namespace`)"; 566 } 567 568 override void accept(Visitor v) 569 { 570 v.visit(this); 571 } 572 573 override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; } 574 } 575 576 /*********************************************************** 577 * Visibility declaration for Dsymbols, e.g. `public int i;` 578 * 579 * `<protection> <decl...>` or 580 * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null` 581 */ 582 extern (C++) final class ProtDeclaration : AttribDeclaration 583 { 584 Prot protection; /// the visibility 585 Identifiers* pkg_identifiers; /// identifiers for `package(foo.bar)` or null 586 587 /** 588 * Params: 589 * loc = source location of attribute token 590 * protection = protection attribute data 591 * decl = declarations which are affected by this protection attribute 592 */ 593 extern (D) this(const ref Loc loc, Prot protection, Dsymbols* decl) 594 { 595 super(loc, null, decl); 596 this.protection = protection; 597 //printf("decl = %p\n", decl); 598 } 599 600 /** 601 * Params: 602 * loc = source location of attribute token 603 * pkg_identifiers = list of identifiers for a qualified package name 604 * decl = declarations which are affected by this protection attribute 605 */ 606 extern (D) this(const ref Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl) 607 { 608 super(loc, null, decl); 609 this.protection.kind = Prot.Kind.package_; 610 this.pkg_identifiers = pkg_identifiers; 611 if (pkg_identifiers !is null && pkg_identifiers.dim > 0) 612 { 613 Dsymbol tmp; 614 Package.resolve(pkg_identifiers, &tmp, null); 615 protection.pkg = tmp ? tmp.isPackage() : null; 616 } 617 } 618 619 override Dsymbol syntaxCopy(Dsymbol s) 620 { 621 assert(!s); 622 if (protection.kind == Prot.Kind.package_) 623 return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl)); 624 else 625 return new ProtDeclaration(this.loc, protection, 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.protection, 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 protection.pkg = tmp ? tmp.isPackage() : null; 642 pkg_identifiers = null; 643 } 644 if (protection.kind == Prot.Kind.package_ && protection.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. protection.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() || !protection.pkg.ident.equals(m.isPackage().ident)) 656 { 657 Package pkg = m.parent ? m.parent.isPackage() : null; 658 if (!pkg || !protection.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 "protection attribute"; 668 } 669 670 override const(char)* toPrettyChars(bool) 671 { 672 assert(protection.kind > Prot.Kind.undefined); 673 OutBuffer buf; 674 protectionToBuffer(&buf, protection); 675 return buf.extractChars(); 676 } 677 678 override inout(ProtDeclaration) isProtDeclaration() 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 Expression ealign; /// expression yielding the actual alignment 698 enum structalign_t UNKNOWN = 0; /// alignment not yet computed 699 static assert(STRUCTALIGN_DEFAULT != UNKNOWN); 700 701 /// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign` 702 /// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred) 703 structalign_t salign = UNKNOWN; 704 705 706 extern (D) this(const ref Loc loc, Expression ealign, Dsymbols* decl) 707 { 708 super(loc, null, decl); 709 this.ealign = ealign; 710 } 711 712 override Dsymbol syntaxCopy(Dsymbol s) 713 { 714 assert(!s); 715 return new AlignDeclaration(loc, 716 ealign ? ealign.syntaxCopy() : null, 717 Dsymbol.arraySyntaxCopy(decl)); 718 } 719 720 override Scope* newScope(Scope* sc) 721 { 722 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining); 723 } 724 725 override void accept(Visitor v) 726 { 727 v.visit(this); 728 } 729 } 730 731 /*********************************************************** 732 * An anonymous struct/union (defined by `isunion`). 733 */ 734 extern (C++) final class AnonDeclaration : AttribDeclaration 735 { 736 bool isunion; /// whether it's a union 737 int sem; /// 1 if successful semantic() 738 uint anonoffset; /// offset of anonymous struct 739 uint anonstructsize; /// size of anonymous struct 740 uint anonalignsize; /// size of anonymous struct for alignment purposes 741 742 extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) 743 { 744 super(loc, null, decl); 745 this.isunion = isunion; 746 } 747 748 override Dsymbol syntaxCopy(Dsymbol s) 749 { 750 assert(!s); 751 return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); 752 } 753 754 override void setScope(Scope* sc) 755 { 756 if (decl) 757 Dsymbol.setScope(sc); 758 return AttribDeclaration.setScope(sc); 759 } 760 761 override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) 762 { 763 //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); 764 if (decl) 765 { 766 /* This works by treating an AnonDeclaration as an aggregate 'member', 767 * so in order to place that member we need to compute the member's 768 * size and alignment. 769 */ 770 size_t fieldstart = ad.fields.dim; 771 772 /* Hackishly hijack ad's structsize and alignsize fields 773 * for use in our fake anon aggregate member. 774 */ 775 uint savestructsize = ad.structsize; 776 uint savealignsize = ad.alignsize; 777 ad.structsize = 0; 778 ad.alignsize = 0; 779 780 uint offset = 0; 781 decl.foreachDsymbol( (s) 782 { 783 s.setFieldOffset(ad, &offset, this.isunion); 784 if (this.isunion) 785 offset = 0; 786 }); 787 788 /* https://issues.dlang.org/show_bug.cgi?id=13613 789 * If the fields in this.members had been already 790 * added in ad.fields, just update *poffset for the subsequent 791 * field offset calculation. 792 */ 793 if (fieldstart == ad.fields.dim) 794 { 795 ad.structsize = savestructsize; 796 ad.alignsize = savealignsize; 797 *poffset = ad.structsize; 798 return; 799 } 800 801 anonstructsize = ad.structsize; 802 anonalignsize = ad.alignsize; 803 ad.structsize = savestructsize; 804 ad.alignsize = savealignsize; 805 806 // 0 sized structs are set to 1 byte 807 if (anonstructsize == 0) 808 { 809 anonstructsize = 1; 810 anonalignsize = 1; 811 } 812 813 assert(_scope); 814 auto alignment = _scope.alignment(); 815 816 /* Given the anon 'member's size and alignment, 817 * go ahead and place it. 818 */ 819 anonoffset = AggregateDeclaration.placeField( 820 poffset, 821 anonstructsize, anonalignsize, alignment, 822 &ad.structsize, &ad.alignsize, 823 isunion); 824 825 // Add to the anon fields the base offset of this anonymous aggregate 826 //printf("anon fields, anonoffset = %d\n", anonoffset); 827 foreach (const i; fieldstart .. ad.fields.dim) 828 { 829 VarDeclaration v = ad.fields[i]; 830 //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); 831 v.offset += anonoffset; 832 } 833 } 834 } 835 836 override const(char)* kind() const 837 { 838 return (isunion ? "anonymous union" : "anonymous struct"); 839 } 840 841 override inout(AnonDeclaration) isAnonDeclaration() inout 842 { 843 return this; 844 } 845 846 override void accept(Visitor v) 847 { 848 v.visit(this); 849 } 850 } 851 852 /*********************************************************** 853 * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`, 854 * but not PragmaStatement's like `pragma(msg, "hello");`. 855 * 856 * pragma(<ident>, <args>) 857 */ 858 extern (C++) final class PragmaDeclaration : AttribDeclaration 859 { 860 Expressions* args; /// parameters of this pragma 861 862 extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) 863 { 864 super(loc, ident, decl); 865 this.args = args; 866 } 867 868 override Dsymbol syntaxCopy(Dsymbol s) 869 { 870 //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); 871 assert(!s); 872 return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); 873 } 874 875 override Scope* newScope(Scope* sc) 876 { 877 if (ident == Id.Pinline) 878 { 879 PINLINE inlining = PINLINE.default_; 880 if (!args || args.dim == 0) 881 inlining = PINLINE.default_; 882 else if (args.dim != 1) 883 { 884 error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim); 885 args.setDim(1); 886 (*args)[0] = ErrorExp.get(); 887 } 888 else 889 { 890 Expression e = (*args)[0]; 891 if (e.op != TOK.int64 || !e.type.equals(Type.tbool)) 892 { 893 if (e.op != TOK.error) 894 { 895 error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars()); 896 (*args)[0] = ErrorExp.get(); 897 } 898 } 899 else if (e.isBool(true)) 900 inlining = PINLINE.always; 901 else if (e.isBool(false)) 902 inlining = PINLINE.never; 903 } 904 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); 905 } 906 if (ident == Id.printf || ident == Id.scanf) 907 { 908 auto sc2 = sc.push(); 909 910 if (ident == Id.printf) 911 // Override previous setting, never let both be set 912 sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf; 913 else 914 sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf; 915 916 return sc2; 917 } 918 return sc; 919 } 920 921 override const(char)* kind() const 922 { 923 return "pragma"; 924 } 925 926 override void accept(Visitor v) 927 { 928 v.visit(this); 929 } 930 } 931 932 /*********************************************************** 933 * A conditional compilation declaration, used for `version` 934 * / `debug` and specialized for `static if`. 935 * 936 * <condition> { <decl...> } else { <elsedecl> } 937 */ 938 extern (C++) class ConditionalDeclaration : AttribDeclaration 939 { 940 Condition condition; /// condition deciding whether decl or elsedecl applies 941 Dsymbols* elsedecl; /// array of Dsymbol's for else block 942 943 extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) 944 { 945 super(decl); 946 //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); 947 this.condition = condition; 948 this.elsedecl = elsedecl; 949 } 950 951 override Dsymbol syntaxCopy(Dsymbol s) 952 { 953 assert(!s); 954 return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); 955 } 956 957 override final bool oneMember(Dsymbol* ps, Identifier ident) 958 { 959 //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); 960 if (condition.inc != Include.notComputed) 961 { 962 Dsymbols* d = condition.include(null) ? decl : elsedecl; 963 return Dsymbol.oneMembers(d, ps, ident); 964 } 965 else 966 { 967 bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); 968 *ps = null; 969 return res; 970 } 971 } 972 973 // Decide if 'then' or 'else' code should be included 974 override Dsymbols* include(Scope* sc) 975 { 976 //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope); 977 978 if (errors) 979 return null; 980 981 assert(condition); 982 return condition.include(_scope ? _scope : sc) ? decl : elsedecl; 983 } 984 985 override final void addComment(const(char)* comment) 986 { 987 /* Because addComment is called by the parser, if we called 988 * include() it would define a version before it was used. 989 * But it's no problem to drill down to both decl and elsedecl, 990 * so that's the workaround. 991 */ 992 if (comment) 993 { 994 decl .foreachDsymbol( s => s.addComment(comment) ); 995 elsedecl.foreachDsymbol( s => s.addComment(comment) ); 996 } 997 } 998 999 override void setScope(Scope* sc) 1000 { 1001 include(sc).foreachDsymbol( s => s.setScope(sc) ); 1002 } 1003 1004 override void accept(Visitor v) 1005 { 1006 v.visit(this); 1007 } 1008 } 1009 1010 /*********************************************************** 1011 * `<scopesym> { 1012 * static if (<condition>) { <decl> } else { <elsedecl> } 1013 * }` 1014 */ 1015 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration 1016 { 1017 ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted 1018 private bool addisdone = false; /// true if members have been added to scope 1019 private bool onStack = false; /// true if a call to `include` is currently active 1020 1021 extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) 1022 { 1023 super(condition, decl, elsedecl); 1024 //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); 1025 } 1026 1027 override Dsymbol syntaxCopy(Dsymbol s) 1028 { 1029 assert(!s); 1030 return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); 1031 } 1032 1033 /**************************************** 1034 * Different from other AttribDeclaration subclasses, include() call requires 1035 * the completion of addMember and setScope phases. 1036 */ 1037 override Dsymbols* include(Scope* sc) 1038 { 1039 //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope); 1040 1041 if (errors || onStack) 1042 return null; 1043 onStack = true; 1044 scope(exit) onStack = false; 1045 1046 if (sc && condition.inc == Include.notComputed) 1047 { 1048 assert(scopesym); // addMember is already done 1049 assert(_scope); // setScope is already done 1050 Dsymbols* d = ConditionalDeclaration.include(_scope); 1051 if (d && !addisdone) 1052 { 1053 // Add members lazily. 1054 d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); 1055 1056 // Set the member scopes lazily. 1057 d.foreachDsymbol( s => s.setScope(_scope) ); 1058 1059 addisdone = true; 1060 } 1061 return d; 1062 } 1063 else 1064 { 1065 return ConditionalDeclaration.include(sc); 1066 } 1067 } 1068 1069 override void addMember(Scope* sc, ScopeDsymbol sds) 1070 { 1071 //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); 1072 /* This is deferred until the condition evaluated later (by the include() call), 1073 * so that expressions in the condition can refer to declarations 1074 * in the same scope, such as: 1075 * 1076 * template Foo(int i) 1077 * { 1078 * const int j = i + 1; 1079 * static if (j == 3) 1080 * const int k; 1081 * } 1082 */ 1083 this.scopesym = sds; 1084 } 1085 1086 override void setScope(Scope* sc) 1087 { 1088 // do not evaluate condition before semantic pass 1089 // But do set the scope, in case we need it for forward referencing 1090 Dsymbol.setScope(sc); 1091 } 1092 1093 override void importAll(Scope* sc) 1094 { 1095 // do not evaluate condition before semantic pass 1096 } 1097 1098 override const(char)* kind() const 1099 { 1100 return "static if"; 1101 } 1102 1103 override void accept(Visitor v) 1104 { 1105 v.visit(this); 1106 } 1107 } 1108 1109 /*********************************************************** 1110 * Static foreach at declaration scope, like: 1111 * static foreach (i; [0, 1, 2]){ } 1112 */ 1113 1114 extern (C++) final class StaticForeachDeclaration : AttribDeclaration 1115 { 1116 StaticForeach sfe; /// contains `static foreach` expansion logic 1117 1118 ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration) 1119 1120 /++ 1121 `include` can be called multiple times, but a `static foreach` 1122 should be expanded at most once. Achieved by caching the result 1123 of the first call. We need both `cached` and `cache`, because 1124 `null` is a valid value for `cache`. 1125 +/ 1126 bool onStack = false; 1127 bool cached = false; 1128 Dsymbols* cache = null; 1129 1130 extern (D) this(StaticForeach sfe, Dsymbols* decl) 1131 { 1132 super(decl); 1133 this.sfe = sfe; 1134 } 1135 1136 override Dsymbol syntaxCopy(Dsymbol s) 1137 { 1138 assert(!s); 1139 return new StaticForeachDeclaration( 1140 sfe.syntaxCopy(), 1141 Dsymbol.arraySyntaxCopy(decl)); 1142 } 1143 1144 override bool oneMember(Dsymbol* ps, Identifier ident) 1145 { 1146 // Required to support IFTI on a template that contains a 1147 // `static foreach` declaration. `super.oneMember` calls 1148 // include with a `null` scope. As `static foreach` requires 1149 // the scope for expansion, `oneMember` can only return a 1150 // precise result once `static foreach` has been expanded. 1151 if (cached) 1152 { 1153 return super.oneMember(ps, ident); 1154 } 1155 *ps = null; // a `static foreach` declaration may in general expand to multiple symbols 1156 return false; 1157 } 1158 1159 override Dsymbols* include(Scope* sc) 1160 { 1161 if (errors || onStack) 1162 return null; 1163 if (cached) 1164 { 1165 assert(!onStack); 1166 return cache; 1167 } 1168 onStack = true; 1169 scope(exit) onStack = false; 1170 1171 if (_scope) 1172 { 1173 sfe.prepare(_scope); // lower static foreach aggregate 1174 } 1175 if (!sfe.ready()) 1176 { 1177 return null; // TODO: ok? 1178 } 1179 1180 // expand static foreach 1181 import dmd.statementsem: makeTupleForeach; 1182 Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion); 1183 if (d) // process generated declarations 1184 { 1185 // Add members lazily. 1186 d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); 1187 1188 // Set the member scopes lazily. 1189 d.foreachDsymbol( s => s.setScope(_scope) ); 1190 } 1191 cached = true; 1192 cache = d; 1193 return d; 1194 } 1195 1196 override void addMember(Scope* sc, ScopeDsymbol sds) 1197 { 1198 // used only for caching the enclosing symbol 1199 this.scopesym = sds; 1200 } 1201 1202 override void addComment(const(char)* comment) 1203 { 1204 // do nothing 1205 // change this to give semantics to documentation comments on static foreach declarations 1206 } 1207 1208 override void setScope(Scope* sc) 1209 { 1210 // do not evaluate condition before semantic pass 1211 // But do set the scope, in case we need it for forward referencing 1212 Dsymbol.setScope(sc); 1213 } 1214 1215 override void importAll(Scope* sc) 1216 { 1217 // do not evaluate aggregate before semantic pass 1218 } 1219 1220 override const(char)* kind() const 1221 { 1222 return "static foreach"; 1223 } 1224 1225 override void accept(Visitor v) 1226 { 1227 v.visit(this); 1228 } 1229 } 1230 1231 /*********************************************************** 1232 * Collection of declarations that stores foreach index variables in a 1233 * local symbol table. Other symbols declared within are forwarded to 1234 * another scope, like: 1235 * 1236 * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict. 1237 * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local 1238 * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable 1239 * } 1240 * 1241 * static foreach (i; 0.. 10) 1242 * { 1243 * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope 1244 * } 1245 * 1246 * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop 1247 * 1248 * A StaticForeachDeclaration generates one 1249 * ForwardingAttribDeclaration for each expansion of its body. The 1250 * AST of the ForwardingAttribDeclaration contains both the `static 1251 * foreach` variables and the respective copy of the `static foreach` 1252 * body. The functionality is achieved by using a 1253 * ForwardingScopeDsymbol as the parent symbol for the generated 1254 * declarations. 1255 */ 1256 1257 extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration 1258 { 1259 ForwardingScopeDsymbol sym = null; 1260 1261 this(Dsymbols* decl) 1262 { 1263 super(decl); 1264 sym = new ForwardingScopeDsymbol(null); 1265 sym.symtab = new DsymbolTable(); 1266 } 1267 1268 /************************************** 1269 * Use the ForwardingScopeDsymbol as the parent symbol for members. 1270 */ 1271 override Scope* newScope(Scope* sc) 1272 { 1273 return sc.push(sym); 1274 } 1275 1276 /*************************************** 1277 * Lazily initializes the scope to forward to. 1278 */ 1279 override void addMember(Scope* sc, ScopeDsymbol sds) 1280 { 1281 parent = sym.parent = sym.forward = sds; 1282 return super.addMember(sc, sym); 1283 } 1284 1285 override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout 1286 { 1287 return this; 1288 } 1289 1290 override void accept(Visitor v) 1291 { 1292 v.visit(this); 1293 } 1294 } 1295 1296 1297 /*********************************************************** 1298 * Mixin declarations, like: 1299 * mixin("int x"); 1300 * https://dlang.org/spec/module.html#mixin-declaration 1301 */ 1302 extern (C++) final class CompileDeclaration : AttribDeclaration 1303 { 1304 Expressions* exps; 1305 ScopeDsymbol scopesym; 1306 bool compiled; 1307 1308 extern (D) this(const ref Loc loc, Expressions* exps) 1309 { 1310 super(loc, null, null); 1311 //printf("CompileDeclaration(loc = %d)\n", loc.linnum); 1312 this.exps = exps; 1313 } 1314 1315 override Dsymbol syntaxCopy(Dsymbol s) 1316 { 1317 //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); 1318 return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps)); 1319 } 1320 1321 override void addMember(Scope* sc, ScopeDsymbol sds) 1322 { 1323 //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); 1324 this.scopesym = sds; 1325 } 1326 1327 override void setScope(Scope* sc) 1328 { 1329 Dsymbol.setScope(sc); 1330 } 1331 1332 override const(char)* kind() const 1333 { 1334 return "mixin"; 1335 } 1336 1337 override inout(CompileDeclaration) isCompileDeclaration() inout 1338 { 1339 return this; 1340 } 1341 1342 override void accept(Visitor v) 1343 { 1344 v.visit(this); 1345 } 1346 } 1347 1348 /*********************************************************** 1349 * User defined attributes look like: 1350 * @foo(args, ...) 1351 * @(args, ...) 1352 */ 1353 extern (C++) final class UserAttributeDeclaration : AttribDeclaration 1354 { 1355 Expressions* atts; 1356 1357 extern (D) this(Expressions* atts, Dsymbols* decl) 1358 { 1359 super(decl); 1360 //printf("UserAttributeDeclaration()\n"); 1361 this.atts = atts; 1362 } 1363 1364 override Dsymbol syntaxCopy(Dsymbol s) 1365 { 1366 //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); 1367 assert(!s); 1368 return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl)); 1369 } 1370 1371 override Scope* newScope(Scope* sc) 1372 { 1373 Scope* sc2 = sc; 1374 if (atts && atts.dim) 1375 { 1376 // create new one for changes 1377 sc2 = sc.copy(); 1378 sc2.userAttribDecl = this; 1379 } 1380 return sc2; 1381 } 1382 1383 override void setScope(Scope* sc) 1384 { 1385 //printf("UserAttributeDeclaration::setScope() %p\n", this); 1386 if (decl) 1387 Dsymbol.setScope(sc); // for forward reference of UDAs 1388 return AttribDeclaration.setScope(sc); 1389 } 1390 1391 extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) 1392 { 1393 Expressions* udas; 1394 if (!udas1 || udas1.dim == 0) 1395 udas = udas2; 1396 else if (!udas2 || udas2.dim == 0) 1397 udas = udas1; 1398 else 1399 { 1400 /* Create a new tuple that combines them 1401 * (do not append to left operand, as this is a copy-on-write operation) 1402 */ 1403 udas = new Expressions(2); 1404 (*udas)[0] = new TupleExp(Loc.initial, udas1); 1405 (*udas)[1] = new TupleExp(Loc.initial, udas2); 1406 } 1407 return udas; 1408 } 1409 1410 Expressions* getAttributes() 1411 { 1412 if (auto sc = _scope) 1413 { 1414 _scope = null; 1415 arrayExpressionSemantic(atts, sc); 1416 } 1417 auto exps = new Expressions(); 1418 if (userAttribDecl && userAttribDecl !is this) 1419 exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes())); 1420 if (atts && atts.dim) 1421 exps.push(new TupleExp(Loc.initial, atts)); 1422 return exps; 1423 } 1424 1425 override const(char)* kind() const 1426 { 1427 return "UserAttribute"; 1428 } 1429 1430 override void accept(Visitor v) 1431 { 1432 v.visit(this); 1433 } 1434 1435 /** 1436 * Check if the provided expression references `core.attribute.gnuAbiTag` 1437 * 1438 * This should be called after semantic has been run on the expression. 1439 * Semantic on UDA happens in semantic2 (see `dmd.semantic2`). 1440 * 1441 * Params: 1442 * e = Expression to check (usually from `UserAttributeDeclaration.atts`) 1443 * 1444 * Returns: 1445 * `true` if the expression references the compiler-recognized `gnuAbiTag` 1446 */ 1447 static bool isGNUABITag(Expression e) 1448 { 1449 if (global.params.cplusplus < CppStdRevision.cpp11) 1450 return false; 1451 1452 auto ts = e.type ? e.type.isTypeStruct() : null; 1453 if (!ts) 1454 return false; 1455 if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent) 1456 return false; 1457 // Can only be defined in druntime 1458 Module m = ts.sym.parent.isModule(); 1459 if (!m || !m.isCoreModule(Id.attribute)) 1460 return false; 1461 return true; 1462 } 1463 1464 /** 1465 * Called from a symbol's semantic to check if `gnuAbiTag` UDA 1466 * can be applied to them 1467 * 1468 * Directly emits an error if the UDA doesn't work with this symbol 1469 * 1470 * Params: 1471 * sym = symbol to check for `gnuAbiTag` 1472 * linkage = Linkage of the symbol (Declaration.link or sc.link) 1473 */ 1474 static void checkGNUABITag(Dsymbol sym, LINK linkage) 1475 { 1476 if (global.params.cplusplus < CppStdRevision.cpp11) 1477 return; 1478 1479 // Avoid `if` at the call site 1480 if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null) 1481 return; 1482 1483 foreach (exp; *sym.userAttribDecl.atts) 1484 { 1485 if (isGNUABITag(exp)) 1486 { 1487 if (sym.isCPPNamespaceDeclaration() || sym.isNspace()) 1488 { 1489 exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars()); 1490 sym.errors = true; 1491 } 1492 else if (linkage != LINK.cpp) 1493 { 1494 exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars()); 1495 sym.errors = true; 1496 } 1497 // Only one `@gnuAbiTag` is allowed by semantic2 1498 return; 1499 } 1500 } 1501 } 1502 }