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