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