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