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.errors; 37 import dmd.expression; 38 import dmd.expressionsem; 39 import dmd.func; 40 import dmd.globals; 41 import dmd.hdrgen : visibilityToBuffer; 42 import dmd.id; 43 import dmd.identifier; 44 import dmd.location; 45 import dmd.mtype; 46 import dmd.objc; // for objc.addSymbols 47 import dmd.common.outbuffer; 48 import dmd.root.array; // for each 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) @safe 61 { 62 this.decl = decl; 63 } 64 65 extern (D) this(const ref Loc loc, Dsymbols* decl) @safe 66 { 67 super(loc, null); 68 this.decl = decl; 69 } 70 71 extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe 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) @safe 232 { 233 super(decl); 234 this.stc = stc; 235 } 236 237 extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl) @safe 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) @safe 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) @safe 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) @safe 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) @safe 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) @safe 528 { 529 super(loc, ident, decl); 530 } 531 532 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl) @safe 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) @safe 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) @safe 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 // https://issues.dlang.org/show_bug.cgi?id=17441 657 // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if 658 // each package's .isModule() properites are equal. 659 // 660 // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. 661 // This breaks package declarations of the package in question if they are declared in 662 // the same package.d file, which _do_ have a module associated with them, and hence a non-null 663 // isModule() 664 if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident)) 665 { 666 Package pkg = m.parent ? m.parent.isPackage() : null; 667 if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg)) 668 .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true)); 669 } 670 } 671 return AttribDeclaration.addMember(sc, sds); 672 } 673 674 override const(char)* kind() const 675 { 676 return "visibility attribute"; 677 } 678 679 override const(char)* toPrettyChars(bool) 680 { 681 assert(visibility.kind > Visibility.Kind.undefined); 682 OutBuffer buf; 683 visibilityToBuffer(buf, visibility); 684 return buf.extractChars(); 685 } 686 687 override inout(VisibilityDeclaration) isVisibilityDeclaration() inout 688 { 689 return this; 690 } 691 692 override void accept(Visitor v) 693 { 694 v.visit(this); 695 } 696 } 697 698 /*********************************************************** 699 * Alignment attribute for aggregates, members and variables. 700 * 701 * `align(<ealign>) <decl...>` or 702 * `align <decl...>` if `ealign` is null 703 */ 704 extern (C++) final class AlignDeclaration : AttribDeclaration 705 { 706 Expressions* exps; /// Expression(s) yielding the desired alignment, 707 /// the largest value wins 708 /// the actual alignment is Unknown until it's either set to the value of `ealign` 709 /// or the default if `ealign` is null ( / an error ocurred) 710 structalign_t salign; 711 712 713 extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl) 714 { 715 super(loc, null, decl); 716 if (exp) 717 { 718 exps = new Expressions(); 719 exps.push(exp); 720 } 721 } 722 723 extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl) @safe 724 { 725 super(loc, null, decl); 726 this.exps = exps; 727 } 728 729 extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl) @safe 730 { 731 super(loc, null, decl); 732 this.salign = salign; 733 } 734 735 override AlignDeclaration syntaxCopy(Dsymbol s) 736 { 737 assert(!s); 738 return new AlignDeclaration(loc, 739 Expression.arraySyntaxCopy(exps), 740 Dsymbol.arraySyntaxCopy(decl)); 741 } 742 743 override Scope* newScope(Scope* sc) 744 { 745 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining); 746 } 747 748 override void accept(Visitor v) 749 { 750 v.visit(this); 751 } 752 } 753 754 /*********************************************************** 755 * An anonymous struct/union (defined by `isunion`). 756 */ 757 extern (C++) final class AnonDeclaration : AttribDeclaration 758 { 759 bool isunion; /// whether it's a union 760 int sem; /// 1 if successful semantic() 761 uint anonoffset; /// offset of anonymous struct 762 uint anonstructsize; /// size of anonymous struct 763 uint anonalignsize; /// size of anonymous struct for alignment purposes 764 765 extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) @safe 766 { 767 super(loc, null, decl); 768 this.isunion = isunion; 769 } 770 771 override AnonDeclaration syntaxCopy(Dsymbol s) 772 { 773 assert(!s); 774 return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); 775 } 776 777 override void setScope(Scope* sc) 778 { 779 if (decl) 780 Dsymbol.setScope(sc); 781 return AttribDeclaration.setScope(sc); 782 } 783 784 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) 785 { 786 //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); 787 if (decl) 788 { 789 /* This works by treating an AnonDeclaration as an aggregate 'member', 790 * so in order to place that member we need to compute the member's 791 * size and alignment. 792 */ 793 size_t fieldstart = ad.fields.length; 794 795 /* Hackishly hijack ad's structsize and alignsize fields 796 * for use in our fake anon aggregate member. 797 */ 798 uint savestructsize = ad.structsize; 799 uint savealignsize = ad.alignsize; 800 ad.structsize = 0; 801 ad.alignsize = 0; 802 803 FieldState fs; 804 decl.foreachDsymbol( (s) 805 { 806 s.setFieldOffset(ad, fs, this.isunion); 807 if (this.isunion) 808 fs.offset = 0; 809 }); 810 811 /* https://issues.dlang.org/show_bug.cgi?id=13613 812 * If the fields in this.members had been already 813 * added in ad.fields, just update *poffset for the subsequent 814 * field offset calculation. 815 */ 816 if (fieldstart == ad.fields.length) 817 { 818 ad.structsize = savestructsize; 819 ad.alignsize = savealignsize; 820 fieldState.offset = ad.structsize; 821 return; 822 } 823 824 anonstructsize = ad.structsize; 825 anonalignsize = ad.alignsize; 826 ad.structsize = savestructsize; 827 ad.alignsize = savealignsize; 828 829 // 0 sized structs are set to 1 byte 830 if (anonstructsize == 0) 831 { 832 anonstructsize = 1; 833 anonalignsize = 1; 834 } 835 836 assert(_scope); 837 auto alignment = _scope.alignment(); 838 839 /* Given the anon 'member's size and alignment, 840 * go ahead and place it. 841 */ 842 anonoffset = placeField( 843 fieldState.offset, 844 anonstructsize, anonalignsize, alignment, 845 ad.structsize, ad.alignsize, 846 isunion); 847 848 // Add to the anon fields the base offset of this anonymous aggregate 849 //printf("anon fields, anonoffset = %d\n", anonoffset); 850 foreach (const i; fieldstart .. ad.fields.length) 851 { 852 VarDeclaration v = ad.fields[i]; 853 //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); 854 v.offset += anonoffset; 855 } 856 } 857 } 858 859 override const(char)* kind() const 860 { 861 return (isunion ? "anonymous union" : "anonymous struct"); 862 } 863 864 override inout(AnonDeclaration) isAnonDeclaration() inout 865 { 866 return this; 867 } 868 869 override void accept(Visitor v) 870 { 871 v.visit(this); 872 } 873 } 874 875 /*********************************************************** 876 * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`, 877 * but not PragmaStatement's like `pragma(msg, "hello");`. 878 * 879 * pragma(<ident>, <args>) 880 */ 881 extern (C++) final class PragmaDeclaration : AttribDeclaration 882 { 883 Expressions* args; /// parameters of this pragma 884 885 extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) @safe 886 { 887 super(loc, ident, decl); 888 this.args = args; 889 } 890 891 override PragmaDeclaration syntaxCopy(Dsymbol s) 892 { 893 //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); 894 assert(!s); 895 return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); 896 } 897 898 override Scope* newScope(Scope* sc) 899 { 900 if (ident == Id.Pinline) 901 { 902 // We keep track of this pragma inside scopes, 903 // then it's evaluated on demand in function semantic 904 return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this); 905 } 906 return sc; 907 } 908 909 override const(char)* kind() const 910 { 911 return "pragma"; 912 } 913 914 override void accept(Visitor v) 915 { 916 v.visit(this); 917 } 918 } 919 920 /*********************************************************** 921 * A conditional compilation declaration, used for `version` 922 * / `debug` and specialized for `static if`. 923 * 924 * <condition> { <decl...> } else { <elsedecl> } 925 */ 926 extern (C++) class ConditionalDeclaration : AttribDeclaration 927 { 928 Condition condition; /// condition deciding whether decl or elsedecl applies 929 Dsymbols* elsedecl; /// array of Dsymbol's for else block 930 931 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe 932 { 933 super(loc, null, decl); 934 //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); 935 this.condition = condition; 936 this.elsedecl = elsedecl; 937 } 938 939 override ConditionalDeclaration syntaxCopy(Dsymbol s) 940 { 941 assert(!s); 942 return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); 943 } 944 945 override final bool oneMember(Dsymbol* ps, Identifier ident) 946 { 947 //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); 948 if (condition.inc != Include.notComputed) 949 { 950 Dsymbols* d = condition.include(null) ? decl : elsedecl; 951 return Dsymbol.oneMembers(d, ps, ident); 952 } 953 else 954 { 955 bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); 956 *ps = null; 957 return res; 958 } 959 } 960 961 // Decide if 'then' or 'else' code should be included 962 override Dsymbols* include(Scope* sc) 963 { 964 //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope); 965 966 if (errors) 967 return null; 968 969 assert(condition); 970 return condition.include(_scope ? _scope : sc) ? decl : elsedecl; 971 } 972 973 override final void addComment(const(char)* comment) 974 { 975 /* Because addComment is called by the parser, if we called 976 * include() it would define a version before it was used. 977 * But it's no problem to drill down to both decl and elsedecl, 978 * so that's the workaround. 979 */ 980 if (comment) 981 { 982 decl .foreachDsymbol( s => s.addComment(comment) ); 983 elsedecl.foreachDsymbol( s => s.addComment(comment) ); 984 } 985 } 986 987 override void setScope(Scope* sc) 988 { 989 include(sc).foreachDsymbol( s => s.setScope(sc) ); 990 } 991 992 override void accept(Visitor v) 993 { 994 v.visit(this); 995 } 996 } 997 998 /*********************************************************** 999 * `<scopesym> { 1000 * static if (<condition>) { <decl> } else { <elsedecl> } 1001 * }` 1002 */ 1003 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration 1004 { 1005 ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted 1006 private bool addisdone = false; /// true if members have been added to scope 1007 private bool onStack = false; /// true if a call to `include` is currently active 1008 1009 extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe 1010 { 1011 super(loc, condition, decl, elsedecl); 1012 //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); 1013 } 1014 1015 override StaticIfDeclaration syntaxCopy(Dsymbol s) 1016 { 1017 assert(!s); 1018 return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); 1019 } 1020 1021 /**************************************** 1022 * Different from other AttribDeclaration subclasses, include() call requires 1023 * the completion of addMember and setScope phases. 1024 */ 1025 override Dsymbols* include(Scope* sc) 1026 { 1027 //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope); 1028 1029 if (errors || onStack) 1030 return null; 1031 onStack = true; 1032 scope(exit) onStack = false; 1033 1034 if (sc && condition.inc == Include.notComputed) 1035 { 1036 assert(scopesym); // addMember is already done 1037 assert(_scope); // setScope is already done 1038 Dsymbols* d = ConditionalDeclaration.include(_scope); 1039 if (d && !addisdone) 1040 { 1041 // Add members lazily. 1042 d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); 1043 1044 // Set the member scopes lazily. 1045 d.foreachDsymbol( s => s.setScope(_scope) ); 1046 1047 addisdone = true; 1048 } 1049 return d; 1050 } 1051 else 1052 { 1053 return ConditionalDeclaration.include(sc); 1054 } 1055 } 1056 1057 override void addMember(Scope* sc, ScopeDsymbol sds) 1058 { 1059 //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); 1060 /* This is deferred until the condition evaluated later (by the include() call), 1061 * so that expressions in the condition can refer to declarations 1062 * in the same scope, such as: 1063 * 1064 * template Foo(int i) 1065 * { 1066 * const int j = i + 1; 1067 * static if (j == 3) 1068 * const int k; 1069 * } 1070 */ 1071 this.scopesym = sds; 1072 } 1073 1074 override void setScope(Scope* sc) 1075 { 1076 // do not evaluate condition before semantic pass 1077 // But do set the scope, in case we need it for forward referencing 1078 Dsymbol.setScope(sc); 1079 } 1080 1081 override void importAll(Scope* sc) 1082 { 1083 // do not evaluate condition before semantic pass 1084 } 1085 1086 override const(char)* kind() const 1087 { 1088 return "static if"; 1089 } 1090 1091 override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe 1092 { 1093 return this; 1094 } 1095 1096 override void accept(Visitor v) 1097 { 1098 v.visit(this); 1099 } 1100 } 1101 1102 /*********************************************************** 1103 * Static foreach at declaration scope, like: 1104 * static foreach (i; [0, 1, 2]){ } 1105 */ 1106 1107 extern (C++) final class StaticForeachDeclaration : AttribDeclaration 1108 { 1109 StaticForeach sfe; /// contains `static foreach` expansion logic 1110 1111 ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration) 1112 1113 /++ 1114 `include` can be called multiple times, but a `static foreach` 1115 should be expanded at most once. Achieved by caching the result 1116 of the first call. We need both `cached` and `cache`, because 1117 `null` is a valid value for `cache`. 1118 +/ 1119 bool onStack = false; 1120 bool cached = false; 1121 Dsymbols* cache = null; 1122 1123 extern (D) this(StaticForeach sfe, Dsymbols* decl) @safe 1124 { 1125 super(sfe.loc, null, decl); 1126 this.sfe = sfe; 1127 } 1128 1129 override StaticForeachDeclaration syntaxCopy(Dsymbol s) 1130 { 1131 assert(!s); 1132 return new StaticForeachDeclaration( 1133 sfe.syntaxCopy(), 1134 Dsymbol.arraySyntaxCopy(decl)); 1135 } 1136 1137 override bool oneMember(Dsymbol* ps, Identifier ident) 1138 { 1139 // Required to support IFTI on a template that contains a 1140 // `static foreach` declaration. `super.oneMember` calls 1141 // include with a `null` scope. As `static foreach` requires 1142 // the scope for expansion, `oneMember` can only return a 1143 // precise result once `static foreach` has been expanded. 1144 if (cached) 1145 { 1146 return super.oneMember(ps, ident); 1147 } 1148 *ps = null; // a `static foreach` declaration may in general expand to multiple symbols 1149 return false; 1150 } 1151 1152 override Dsymbols* include(Scope* sc) 1153 { 1154 if (errors || onStack) 1155 return null; 1156 if (cached) 1157 { 1158 assert(!onStack); 1159 return cache; 1160 } 1161 onStack = true; 1162 scope(exit) onStack = false; 1163 1164 if (_scope) 1165 { 1166 sfe.prepare(_scope); // lower static foreach aggregate 1167 } 1168 if (!sfe.ready()) 1169 { 1170 return null; // TODO: ok? 1171 } 1172 1173 // expand static foreach 1174 import dmd.statementsem: makeTupleForeach; 1175 Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl; 1176 if (d) // process generated declarations 1177 { 1178 // Add members lazily. 1179 d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); 1180 1181 // Set the member scopes lazily. 1182 d.foreachDsymbol( s => s.setScope(_scope) ); 1183 } 1184 cached = true; 1185 cache = d; 1186 return d; 1187 } 1188 1189 override void addMember(Scope* sc, ScopeDsymbol sds) 1190 { 1191 // used only for caching the enclosing symbol 1192 this.scopesym = sds; 1193 } 1194 1195 override void addComment(const(char)* comment) 1196 { 1197 // do nothing 1198 // change this to give semantics to documentation comments on static foreach declarations 1199 } 1200 1201 override void setScope(Scope* sc) 1202 { 1203 // do not evaluate condition before semantic pass 1204 // But do set the scope, in case we need it for forward referencing 1205 Dsymbol.setScope(sc); 1206 } 1207 1208 override void importAll(Scope* sc) 1209 { 1210 // do not evaluate aggregate before semantic pass 1211 } 1212 1213 override const(char)* kind() const 1214 { 1215 return "static foreach"; 1216 } 1217 1218 override void accept(Visitor v) 1219 { 1220 v.visit(this); 1221 } 1222 } 1223 1224 /*********************************************************** 1225 * Collection of declarations that stores foreach index variables in a 1226 * local symbol table. Other symbols declared within are forwarded to 1227 * another scope, like: 1228 * 1229 * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict. 1230 * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local 1231 * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable 1232 * } 1233 * 1234 * static foreach (i; 0.. 10) 1235 * { 1236 * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope 1237 * } 1238 * 1239 * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop 1240 * 1241 * A StaticForeachDeclaration generates one 1242 * ForwardingAttribDeclaration for each expansion of its body. The 1243 * AST of the ForwardingAttribDeclaration contains both the `static 1244 * foreach` variables and the respective copy of the `static foreach` 1245 * body. The functionality is achieved by using a 1246 * ForwardingScopeDsymbol as the parent symbol for the generated 1247 * declarations. 1248 */ 1249 1250 extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration 1251 { 1252 ForwardingScopeDsymbol sym = null; 1253 1254 this(Dsymbols* decl) @safe 1255 { 1256 super(decl); 1257 sym = new ForwardingScopeDsymbol(); 1258 sym.symtab = new DsymbolTable(); 1259 } 1260 1261 /************************************** 1262 * Use the ForwardingScopeDsymbol as the parent symbol for members. 1263 */ 1264 override Scope* newScope(Scope* sc) 1265 { 1266 return sc.push(sym); 1267 } 1268 1269 /*************************************** 1270 * Lazily initializes the scope to forward to. 1271 */ 1272 override void addMember(Scope* sc, ScopeDsymbol sds) 1273 { 1274 sym.parent = sds; 1275 return super.addMember(sc, sym); 1276 } 1277 1278 override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout 1279 { 1280 return this; 1281 } 1282 1283 override void accept(Visitor v) 1284 { 1285 v.visit(this); 1286 } 1287 } 1288 1289 1290 /*********************************************************** 1291 * Mixin declarations, like: 1292 * mixin("int x"); 1293 * https://dlang.org/spec/module.html#mixin-declaration 1294 */ 1295 // Note: was CompileDeclaration 1296 extern (C++) final class MixinDeclaration : AttribDeclaration 1297 { 1298 Expressions* exps; 1299 ScopeDsymbol scopesym; 1300 bool compiled; 1301 1302 extern (D) this(const ref Loc loc, Expressions* exps) @safe 1303 { 1304 super(loc, null, null); 1305 //printf("MixinDeclaration(loc = %d)\n", loc.linnum); 1306 this.exps = exps; 1307 } 1308 1309 override MixinDeclaration syntaxCopy(Dsymbol s) 1310 { 1311 //printf("MixinDeclaration::syntaxCopy('%s')\n", toChars()); 1312 return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps)); 1313 } 1314 1315 override void addMember(Scope* sc, ScopeDsymbol sds) 1316 { 1317 //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); 1318 this.scopesym = sds; 1319 } 1320 1321 override void setScope(Scope* sc) 1322 { 1323 Dsymbol.setScope(sc); 1324 } 1325 1326 override const(char)* kind() const 1327 { 1328 return "mixin"; 1329 } 1330 1331 override inout(MixinDeclaration) isMixinDeclaration() inout 1332 { 1333 return this; 1334 } 1335 1336 override void accept(Visitor v) 1337 { 1338 v.visit(this); 1339 } 1340 } 1341 1342 /*********************************************************** 1343 * User defined attributes look like: 1344 * @foo(args, ...) 1345 * @(args, ...) 1346 */ 1347 extern (C++) final class UserAttributeDeclaration : AttribDeclaration 1348 { 1349 Expressions* atts; 1350 1351 extern (D) this(Expressions* atts, Dsymbols* decl) @safe 1352 { 1353 super(decl); 1354 this.atts = atts; 1355 } 1356 1357 override UserAttributeDeclaration syntaxCopy(Dsymbol s) 1358 { 1359 //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); 1360 assert(!s); 1361 return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl)); 1362 } 1363 1364 override Scope* newScope(Scope* sc) 1365 { 1366 Scope* sc2 = sc; 1367 if (atts && atts.length) 1368 { 1369 // create new one for changes 1370 sc2 = sc.copy(); 1371 sc2.userAttribDecl = this; 1372 } 1373 return sc2; 1374 } 1375 1376 override void setScope(Scope* sc) 1377 { 1378 //printf("UserAttributeDeclaration::setScope() %p\n", this); 1379 if (decl) 1380 Dsymbol.setScope(sc); // for forward reference of UDAs 1381 return AttribDeclaration.setScope(sc); 1382 } 1383 1384 extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) 1385 { 1386 Expressions* udas; 1387 if (!udas1 || udas1.length == 0) 1388 udas = udas2; 1389 else if (!udas2 || udas2.length == 0) 1390 udas = udas1; 1391 else 1392 { 1393 /* Create a new tuple that combines them 1394 * (do not append to left operand, as this is a copy-on-write operation) 1395 */ 1396 udas = new Expressions(2); 1397 (*udas)[0] = new TupleExp(Loc.initial, udas1); 1398 (*udas)[1] = new TupleExp(Loc.initial, udas2); 1399 } 1400 return udas; 1401 } 1402 1403 Expressions* getAttributes() 1404 { 1405 if (auto sc = _scope) 1406 { 1407 _scope = null; 1408 arrayExpressionSemantic(atts.peekSlice(), sc); 1409 } 1410 auto exps = new Expressions(); 1411 if (userAttribDecl && userAttribDecl !is this) 1412 exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes())); 1413 if (atts && atts.length) 1414 exps.push(new TupleExp(Loc.initial, atts)); 1415 return exps; 1416 } 1417 1418 override const(char)* kind() const 1419 { 1420 return "UserAttribute"; 1421 } 1422 1423 override void accept(Visitor v) 1424 { 1425 v.visit(this); 1426 } 1427 1428 /** 1429 * Check if the provided expression references `core.attribute.gnuAbiTag` 1430 * 1431 * This should be called after semantic has been run on the expression. 1432 * Semantic on UDA happens in semantic2 (see `dmd.semantic2`). 1433 * 1434 * Params: 1435 * e = Expression to check (usually from `UserAttributeDeclaration.atts`) 1436 * 1437 * Returns: 1438 * `true` if the expression references the compiler-recognized `gnuAbiTag` 1439 */ 1440 static bool isGNUABITag(Expression e) 1441 { 1442 if (global.params.cplusplus < CppStdRevision.cpp11) 1443 return false; 1444 1445 auto ts = e.type ? e.type.isTypeStruct() : null; 1446 if (!ts) 1447 return false; 1448 if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent) 1449 return false; 1450 // Can only be defined in druntime 1451 Module m = ts.sym.parent.isModule(); 1452 if (!m || !m.isCoreModule(Id.attribute)) 1453 return false; 1454 return true; 1455 } 1456 1457 /** 1458 * Called from a symbol's semantic to check if `gnuAbiTag` UDA 1459 * can be applied to them 1460 * 1461 * Directly emits an error if the UDA doesn't work with this symbol 1462 * 1463 * Params: 1464 * sym = symbol to check for `gnuAbiTag` 1465 * linkage = Linkage of the symbol (Declaration.link or sc.link) 1466 */ 1467 static void checkGNUABITag(Dsymbol sym, LINK linkage) 1468 { 1469 if (global.params.cplusplus < CppStdRevision.cpp11) 1470 return; 1471 1472 foreachUdaNoSemantic(sym, (exp) { 1473 if (isGNUABITag(exp)) 1474 { 1475 if (sym.isCPPNamespaceDeclaration() || sym.isNspace()) 1476 { 1477 .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars()); 1478 sym.errors = true; 1479 } 1480 else if (linkage != LINK.cpp) 1481 { 1482 .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars()); 1483 sym.errors = true; 1484 } 1485 // Only one `@gnuAbiTag` is allowed by semantic2 1486 return 1; // break 1487 } 1488 return 0; // continue 1489 }); 1490 } 1491 } 1492 1493 /** 1494 * Returns `true` if the given symbol is a symbol declared in 1495 * `core.attribute` and has the given identifier. 1496 * 1497 * This is used to determine if a symbol is a UDA declared in 1498 * `core.attribute`. 1499 * 1500 * Params: 1501 * sym = the symbol to check 1502 * ident = the name of the expected UDA 1503 */ 1504 bool isCoreUda(Dsymbol sym, Identifier ident) 1505 { 1506 if (sym.ident != ident || !sym.parent) 1507 return false; 1508 1509 auto _module = sym.parent.isModule(); 1510 return _module && _module.isCoreModule(Id.attribute); 1511 } 1512 1513 /** 1514 * Iterates the UDAs attached to the given symbol. 1515 * 1516 * Params: 1517 * sym = the symbol to get the UDAs from 1518 * sc = scope to use for semantic analysis of UDAs 1519 * dg = called once for each UDA 1520 * 1521 * Returns: 1522 * If `dg` returns `!= 0`, stops the iteration and returns that value. 1523 * Otherwise, returns 0. 1524 */ 1525 int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg) 1526 { 1527 if (!sym.userAttribDecl) 1528 return 0; 1529 1530 auto udas = sym.userAttribDecl.getAttributes(); 1531 arrayExpressionSemantic(udas.peekSlice(), sc, true); 1532 1533 return udas.each!((uda) { 1534 if (!uda.isTupleExp()) 1535 return 0; 1536 1537 auto exps = uda.isTupleExp().exps; 1538 1539 return exps.each!((e) { 1540 assert(e); 1541 1542 if (auto result = dg(e)) 1543 return result; 1544 1545 return 0; 1546 }); 1547 }); 1548 } 1549 1550 /** 1551 * Iterates the UDAs attached to the given symbol, without performing semantic 1552 * analysis. 1553 * 1554 * Use this function instead of `foreachUda` if semantic analysis of `sym` is 1555 * still in progress. 1556 * 1557 * Params: 1558 * sym = the symbol to get the UDAs from 1559 * dg = called once for each UDA 1560 * 1561 * Returns: 1562 * If `dg` returns `!= 0`, stops the iteration and returns that value. 1563 * Otherwise, returns 0. 1564 */ 1565 int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg) 1566 { 1567 if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null) 1568 return 0; 1569 1570 foreach (exp; *sym.userAttribDecl.atts) 1571 { 1572 if (auto result = dg(exp)) 1573 return result; 1574 } 1575 1576 return 0; 1577 }