1 /** 2 * The base class for a D symbol, which can be a module, variable, function, enum, etc. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d) 8 * Documentation: https://dlang.org/phobos/dmd_dsymbol.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d 10 */ 11 12 module dmd.dsymbol; 13 14 import core.stdc.stdarg; 15 import core.stdc.stdio; 16 import core.stdc.string; 17 import core.stdc.stdlib; 18 19 import dmd.aggregate; 20 import dmd.aliasthis; 21 import dmd.arraytypes; 22 import dmd.attrib; 23 import dmd.astenums; 24 import dmd.ast_node; 25 import dmd.gluelayer; 26 import dmd.dclass; 27 import dmd.declaration; 28 import dmd.denum; 29 import dmd.dimport; 30 import dmd.dmodule; 31 import dmd.dversion; 32 import dmd.dscope; 33 import dmd.dstruct; 34 import dmd.dsymbolsem; 35 import dmd.dtemplate; 36 import dmd.errors; 37 import dmd.expression; 38 import dmd.expressionsem; 39 import dmd.func; 40 import dmd.globals; 41 import dmd.id; 42 import dmd.identifier; 43 import dmd.init; 44 import dmd.lexer; 45 import dmd.location; 46 import dmd.mtype; 47 import dmd.nspace; 48 import dmd.opover; 49 import dmd.root.aav; 50 import dmd.root.rmem; 51 import dmd.root.rootobject; 52 import dmd.root.speller; 53 import dmd.root.string; 54 import dmd.statement; 55 import dmd.staticassert; 56 import dmd.tokens; 57 import dmd.visitor; 58 59 /*************************************** 60 * Calls dg(Dsymbol *sym) for each Dsymbol. 61 * If dg returns !=0, stops and returns that value else returns 0. 62 * Params: 63 * symbols = Dsymbols 64 * dg = delegate to call for each Dsymbol 65 * Returns: 66 * last value returned by dg() 67 * 68 * See_Also: $(REF each, dmd, root, array) 69 */ 70 int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg) 71 { 72 assert(dg); 73 if (symbols) 74 { 75 /* Do not use foreach, as the size of the array may expand during iteration 76 */ 77 for (size_t i = 0; i < symbols.length; ++i) 78 { 79 Dsymbol s = (*symbols)[i]; 80 const result = dg(s); 81 if (result) 82 return result; 83 } 84 } 85 return 0; 86 } 87 88 /*************************************** 89 * Calls dg(Dsymbol *sym) for each Dsymbol. 90 * Params: 91 * symbols = Dsymbols 92 * dg = delegate to call for each Dsymbol 93 * 94 * See_Also: $(REF each, dmd, root, array) 95 */ 96 void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg) 97 { 98 assert(dg); 99 if (symbols) 100 { 101 /* Do not use foreach, as the size of the array may expand during iteration 102 */ 103 for (size_t i = 0; i < symbols.length; ++i) 104 { 105 Dsymbol s = (*symbols)[i]; 106 dg(s); 107 } 108 } 109 } 110 111 112 struct Ungag 113 { 114 uint oldgag; 115 116 extern (D) this(uint old) nothrow 117 { 118 this.oldgag = old; 119 } 120 121 extern (C++) ~this() nothrow 122 { 123 global.gag = oldgag; 124 } 125 } 126 127 struct Visibility 128 { 129 /// 130 enum Kind : ubyte 131 { 132 undefined, 133 none, // no access 134 private_, 135 package_, 136 protected_, 137 public_, 138 export_, 139 } 140 141 Kind kind; 142 Package pkg; 143 144 extern (D): 145 146 this(Visibility.Kind kind) pure nothrow @nogc @safe 147 { 148 this.kind = kind; 149 } 150 151 /** 152 * Checks if `this` is less or more visible than `other` 153 * 154 * Params: 155 * other = Visibility to compare `this` to. 156 * 157 * Returns: 158 * A value `< 0` if `this` is less visible than `other`, 159 * a value `> 0` if `this` is more visible than `other`, 160 * and `0` if they are at the same level. 161 * Note that `package` visibility with different packages 162 * will also return `0`. 163 */ 164 int opCmp(const Visibility other) const pure nothrow @nogc @safe 165 { 166 return this.kind - other.kind; 167 } 168 169 /// 170 unittest 171 { 172 assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_)); 173 assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_)); 174 assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_)); 175 } 176 177 /** 178 * Checks if `this` is absolutely identical visibility attribute to `other` 179 */ 180 bool opEquals(ref const Visibility other) const 181 { 182 if (this.kind == other.kind) 183 { 184 if (this.kind == Visibility.Kind.package_) 185 return this.pkg == other.pkg; 186 return true; 187 } 188 return false; 189 } 190 } 191 192 enum PASS : ubyte 193 { 194 initial, // initial state 195 semantic, // semantic() started 196 semanticdone, // semantic() done 197 semantic2, // semantic2() started 198 semantic2done, // semantic2() done 199 semantic3, // semantic3() started 200 semantic3done, // semantic3() done 201 inline, // inline started 202 inlinedone, // inline done 203 obj, // toObjFile() run 204 } 205 206 // Search options 207 enum : int 208 { 209 IgnoreNone = 0x00, // default 210 IgnorePrivateImports = 0x01, // don't search private imports 211 IgnoreErrors = 0x02, // don't give error messages 212 IgnoreAmbiguous = 0x04, // return NULL if ambiguous 213 SearchLocalsOnly = 0x08, // only look at locals (don't search imports) 214 SearchImportsOnly = 0x10, // only look in imports 215 SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, 216 // meaning don't search imports in that scope, 217 // because qualified module searches search 218 // their imports 219 IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols 220 TagNameSpace = 0x100, // search ImportC tag symbol table 221 } 222 223 /*********************************************************** 224 * Struct/Class/Union field state. 225 * Used for transitory information when setting field offsets, such 226 * as bit fields. 227 */ 228 struct FieldState 229 { 230 uint offset; /// byte offset for next field 231 232 uint fieldOffset; /// byte offset for the start of the bit field 233 uint fieldSize; /// byte size of field 234 uint fieldAlign; /// byte alignment of field 235 uint bitOffset; /// bit offset for field 236 237 bool inFlight; /// bit field is in flight 238 } 239 240 // 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos), 241 // so save memory by grouping them into a separate struct 242 private struct DsymbolAttributes 243 { 244 /// C++ namespace this symbol belongs to 245 CPPNamespaceDeclaration cppnamespace; 246 /// customized deprecation message 247 DeprecatedDeclaration depdecl_; 248 /// user defined attributes 249 UserAttributeDeclaration userAttribDecl; 250 } 251 252 /*********************************************************** 253 */ 254 extern (C++) class Dsymbol : ASTNode 255 { 256 Identifier ident; 257 Dsymbol parent; 258 Symbol* csym; // symbol for code generator 259 const Loc loc; // where defined 260 Scope* _scope; // !=null means context to use for semantic() 261 const(char)* prettystring; // cached value of toPrettyChars() 262 private DsymbolAttributes* atts; /// attached attribute declarations 263 bool errors; // this symbol failed to pass semantic() 264 PASS semanticRun = PASS.initial; 265 ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab 266 267 final extern (D) this() nothrow 268 { 269 //printf("Dsymbol::Dsymbol(%p)\n", this); 270 loc = Loc(null, 0, 0); 271 } 272 273 final extern (D) this(Identifier ident) nothrow 274 { 275 //printf("Dsymbol::Dsymbol(%p, ident)\n", this); 276 this.loc = Loc(null, 0, 0); 277 this.ident = ident; 278 } 279 280 final extern (D) this(const ref Loc loc, Identifier ident) nothrow 281 { 282 //printf("Dsymbol::Dsymbol(%p, ident)\n", this); 283 this.loc = loc; 284 this.ident = ident; 285 } 286 287 static Dsymbol create(Identifier ident) nothrow 288 { 289 return new Dsymbol(ident); 290 } 291 292 override const(char)* toChars() const 293 { 294 return ident ? ident.toChars() : "__anonymous"; 295 } 296 297 // Getters / setters for fields stored in `DsymbolAttributes` 298 final nothrow pure @safe 299 { 300 private ref DsymbolAttributes getAtts() 301 { 302 if (!atts) 303 atts = new DsymbolAttributes(); 304 return *atts; 305 } 306 307 inout(DeprecatedDeclaration) depdecl() inout { return atts ? atts.depdecl_ : null; } 308 inout(CPPNamespaceDeclaration) cppnamespace() inout { return atts ? atts.cppnamespace : null; } 309 inout(UserAttributeDeclaration) userAttribDecl() inout { return atts ? atts.userAttribDecl : null; } 310 311 DeprecatedDeclaration depdecl(DeprecatedDeclaration dd) 312 { 313 if (!dd && !atts) 314 return null; 315 return getAtts().depdecl_ = dd; 316 } 317 318 CPPNamespaceDeclaration cppnamespace(CPPNamespaceDeclaration ns) 319 { 320 if (!ns && !atts) 321 return null; 322 return getAtts().cppnamespace = ns; 323 } 324 325 UserAttributeDeclaration userAttribDecl(UserAttributeDeclaration uad) 326 { 327 if (!uad && !atts) 328 return null; 329 return getAtts().userAttribDecl = uad; 330 } 331 } 332 333 // helper to print fully qualified (template) arguments 334 const(char)* toPrettyCharsHelper() 335 { 336 return toChars(); 337 } 338 339 final const(Loc) getLoc() 340 { 341 if (!loc.isValid()) // avoid bug 5861. 342 if (const m = getModule()) 343 return Loc(m.srcfile.toChars(), 0, 0); 344 return loc; 345 } 346 347 final const(char)* locToChars() 348 { 349 return getLoc().toChars(); 350 } 351 352 override bool equals(const RootObject o) const 353 { 354 if (this == o) 355 return true; 356 if (o.dyncast() != DYNCAST.dsymbol) 357 return false; 358 auto s = cast(Dsymbol)o; 359 // Overload sets don't have an ident 360 // Function-local declarations may have identical names 361 // if they are declared in different scopes 362 if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum) 363 return true; 364 return false; 365 } 366 367 final bool isAnonymous() const 368 { 369 return ident is null || ident.isAnonymous; 370 } 371 372 extern(D) private const(char)[] prettyFormatHelper() 373 { 374 const cstr = toPrettyChars(); 375 return '`' ~ cstr.toDString() ~ "`\0"; 376 } 377 378 static if (__VERSION__ < 2092) 379 { 380 final void error(const ref Loc loc, const(char)* format, ...) 381 { 382 va_list ap; 383 va_start(ap, format); 384 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr); 385 va_end(ap); 386 } 387 388 final void error(const(char)* format, ...) 389 { 390 va_list ap; 391 va_start(ap, format); 392 const loc = getLoc(); 393 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr); 394 va_end(ap); 395 } 396 397 final void deprecation(const ref Loc loc, const(char)* format, ...) 398 { 399 va_list ap; 400 va_start(ap, format); 401 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr); 402 va_end(ap); 403 } 404 405 final void deprecation(const(char)* format, ...) 406 { 407 va_list ap; 408 va_start(ap, format); 409 const loc = getLoc(); 410 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr); 411 va_end(ap); 412 } 413 } 414 else 415 { 416 pragma(printf) final void error(const ref Loc loc, const(char)* format, ...) 417 { 418 va_list ap; 419 va_start(ap, format); 420 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr); 421 va_end(ap); 422 } 423 424 pragma(printf) final void error(const(char)* format, ...) 425 { 426 va_list ap; 427 va_start(ap, format); 428 const loc = getLoc(); 429 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr); 430 va_end(ap); 431 } 432 433 pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...) 434 { 435 va_list ap; 436 va_start(ap, format); 437 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr); 438 va_end(ap); 439 } 440 441 pragma(printf) final void deprecation(const(char)* format, ...) 442 { 443 va_list ap; 444 va_start(ap, format); 445 const loc = getLoc(); 446 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr); 447 va_end(ap); 448 } 449 } 450 451 final bool checkDeprecated(const ref Loc loc, Scope* sc) 452 { 453 if (global.params.useDeprecated == DiagnosticReporting.off) 454 return false; 455 if (!this.isDeprecated()) 456 return false; 457 // Don't complain if we're inside a deprecated symbol's scope 458 if (sc.isDeprecated()) 459 return false; 460 // Don't complain if we're inside a template constraint 461 // https://issues.dlang.org/show_bug.cgi?id=21831 462 if (sc.flags & SCOPE.constraint) 463 return false; 464 465 const(char)* message = null; 466 for (Dsymbol p = this; p; p = p.parent) 467 { 468 message = p.depdecl ? p.depdecl.getMessage() : null; 469 if (message) 470 break; 471 } 472 if (message) 473 deprecation(loc, "is deprecated - %s", message); 474 else 475 deprecation(loc, "is deprecated"); 476 477 if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) 478 ti.printInstantiationTrace(Classification.deprecation); 479 else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null) 480 ti.printInstantiationTrace(Classification.deprecation); 481 482 return true; 483 } 484 485 /********************************** 486 * Determine which Module a Dsymbol is in. 487 */ 488 final Module getModule() 489 { 490 //printf("Dsymbol::getModule()\n"); 491 if (TemplateInstance ti = isInstantiated()) 492 return ti.tempdecl.getModule(); 493 Dsymbol s = this; 494 while (s) 495 { 496 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars()); 497 Module m = s.isModule(); 498 if (m) 499 return m; 500 s = s.parent; 501 } 502 return null; 503 } 504 505 /************************************** 506 * Does this Dsymbol come from a C file? 507 * Returns: 508 * true if it does 509 */ 510 final bool isCsymbol() 511 { 512 if (Module m = getModule()) 513 return m.filetype == FileType.c; 514 return false; 515 } 516 517 /********************************** 518 * Determine which Module a Dsymbol is in, as far as access rights go. 519 */ 520 final Module getAccessModule() 521 { 522 //printf("Dsymbol::getAccessModule()\n"); 523 if (TemplateInstance ti = isInstantiated()) 524 return ti.tempdecl.getAccessModule(); 525 Dsymbol s = this; 526 while (s) 527 { 528 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars()); 529 Module m = s.isModule(); 530 if (m) 531 return m; 532 TemplateInstance ti = s.isTemplateInstance(); 533 if (ti && ti.enclosing) 534 { 535 /* Because of local template instantiation, the parent isn't where the access 536 * rights come from - it's the template declaration 537 */ 538 s = ti.tempdecl; 539 } 540 else 541 s = s.parent; 542 } 543 return null; 544 } 545 546 /** 547 * `pastMixin` returns the enclosing symbol if this is a template mixin. 548 * 549 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that 550 * are mangleOnly. 551 * 552 * See also `parent`, `toParent` and `toParent2`. 553 */ 554 final inout(Dsymbol) pastMixin() inout 555 { 556 //printf("Dsymbol::pastMixin() %s\n", toChars()); 557 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol()) 558 return this; 559 if (!parent) 560 return null; 561 return parent.pastMixin(); 562 } 563 564 /********************************** 565 * `parent` field returns a lexically enclosing scope symbol this is a member of. 566 * 567 * `toParent()` returns a logically enclosing scope symbol this is a member of. 568 * It skips over TemplateMixin's. 569 * 570 * `toParent2()` returns an enclosing scope symbol this is living at runtime. 571 * It skips over both TemplateInstance's and TemplateMixin's. 572 * It's used when looking for the 'this' pointer of the enclosing function/class. 573 * 574 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope 575 * instead of the instantiation scope. 576 * 577 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope 578 * if a template declaration is non-local i.e. global or static. 579 * 580 * Examples: 581 * --- 582 * module mod; 583 * template Foo(alias a) { mixin Bar!(); } 584 * mixin template Bar() { 585 * public { // VisibilityDeclaration 586 * void baz() { a = 2; } 587 * } 588 * } 589 * void test() { 590 * int v = 1; 591 * alias foo = Foo!(v); 592 * foo.baz(); 593 * assert(v == 2); 594 * } 595 * 596 * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()') 597 * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()') 598 * // s.toParent() == TemplateInstance('mod.test.Foo!()') 599 * // s.toParent2() == FuncDeclaration('mod.test') 600 * // s.toParentDecl() == Module('mod') 601 * // s.toParentLocal() == FuncDeclaration('mod.test') 602 * --- 603 */ 604 final inout(Dsymbol) toParent() inout 605 { 606 return parent ? parent.pastMixin() : null; 607 } 608 609 /// ditto 610 final inout(Dsymbol) toParent2() inout 611 { 612 if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol()) 613 return parent; 614 return parent.toParent2; 615 } 616 617 /// ditto 618 final inout(Dsymbol) toParentDecl() inout 619 { 620 return toParentDeclImpl(false); 621 } 622 623 /// ditto 624 final inout(Dsymbol) toParentLocal() inout 625 { 626 return toParentDeclImpl(true); 627 } 628 629 private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout 630 { 631 auto p = toParent(); 632 if (!p || !p.isTemplateInstance()) 633 return p; 634 auto ti = p.isTemplateInstance(); 635 if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic)) 636 return ti.tempdecl.toParentDeclImpl(localOnly); 637 return parent.toParentDeclImpl(localOnly); 638 } 639 640 /** 641 * Returns the declaration scope scope of `this` unless any of the symbols 642 * `p1` or `p2` resides in its enclosing instantiation scope then the 643 * latter is returned. 644 */ 645 final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null) 646 { 647 return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal(); 648 } 649 650 final inout(TemplateInstance) isInstantiated() inout 651 { 652 if (!parent) 653 return null; 654 auto ti = parent.isTemplateInstance(); 655 if (ti && !ti.isTemplateMixin()) 656 return ti; 657 return parent.isInstantiated(); 658 } 659 660 /*** 661 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing 662 * instantiation scope of `this`. 663 */ 664 final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null) 665 { 666 static bool has2This(Dsymbol s) 667 { 668 if (auto f = s.isFuncDeclaration()) 669 return f.hasDualContext(); 670 if (auto ad = s.isAggregateDeclaration()) 671 return ad.vthis2 !is null; 672 return false; 673 } 674 675 if (has2This(this)) 676 { 677 assert(p1); 678 auto outer = toParent(); 679 while (outer) 680 { 681 auto ti = outer.isTemplateInstance(); 682 if (!ti) 683 break; 684 foreach (oarg; *ti.tiargs) 685 { 686 auto sa = getDsymbol(oarg); 687 if (!sa) 688 continue; 689 sa = sa.toAlias().toParent2(); 690 if (!sa) 691 continue; 692 if (sa == p1) 693 return true; 694 else if (p2 && sa == p2) 695 return true; 696 } 697 outer = ti.tempdecl.toParent(); 698 } 699 return false; 700 } 701 return false; 702 } 703 704 // Check if this function is a member of a template which has only been 705 // instantiated speculatively, eg from inside is(typeof()). 706 // Return the speculative template instance it is part of, 707 // or NULL if not speculative. 708 final inout(TemplateInstance) isSpeculative() inout 709 { 710 if (!parent) 711 return null; 712 auto ti = parent.isTemplateInstance(); 713 if (ti && ti.gagged) 714 return ti; 715 if (!parent.toParent()) 716 return null; 717 return parent.isSpeculative(); 718 } 719 720 final Ungag ungagSpeculative() const 721 { 722 uint oldgag = global.gag; 723 if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration()) 724 global.gag = 0; 725 return Ungag(oldgag); 726 } 727 728 // kludge for template.isSymbol() 729 override final DYNCAST dyncast() const 730 { 731 return DYNCAST.dsymbol; 732 } 733 734 /************************************* 735 * Do syntax copy of an array of Dsymbol's. 736 */ 737 extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a) 738 { 739 Dsymbols* b = null; 740 if (a) 741 { 742 b = a.copy(); 743 for (size_t i = 0; i < b.length; i++) 744 { 745 (*b)[i] = (*b)[i].syntaxCopy(null); 746 } 747 } 748 return b; 749 } 750 751 Identifier getIdent() 752 { 753 return ident; 754 } 755 756 const(char)* toPrettyChars(bool QualifyTypes = false) 757 { 758 if (prettystring && !QualifyTypes) 759 return prettystring; 760 761 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); 762 if (!parent) 763 { 764 auto s = toChars(); 765 if (!QualifyTypes) 766 prettystring = s; 767 return s; 768 } 769 770 // Computer number of components 771 size_t complength = 0; 772 for (Dsymbol p = this; p; p = p.parent) 773 ++complength; 774 775 // Allocate temporary array comp[] 776 alias T = const(char)[]; 777 auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof)); 778 auto comp = compptr[0 .. complength]; 779 780 // Fill in comp[] and compute length of final result 781 size_t length = 0; 782 int i; 783 for (Dsymbol p = this; p; p = p.parent) 784 { 785 const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars(); 786 const len = strlen(s); 787 comp[i] = s[0 .. len]; 788 ++i; 789 length += len + 1; 790 } 791 792 auto s = cast(char*)mem.xmalloc_noscan(length); 793 auto q = s + length - 1; 794 *q = 0; 795 foreach (j; 0 .. complength) 796 { 797 const t = comp[j].ptr; 798 const len = comp[j].length; 799 q -= len; 800 memcpy(q, t, len); 801 if (q == s) 802 break; 803 *--q = '.'; 804 } 805 free(comp.ptr); 806 if (!QualifyTypes) 807 prettystring = s; 808 return s; 809 } 810 811 const(char)* kind() const pure nothrow @nogc @safe 812 { 813 return "symbol"; 814 } 815 816 /********************************* 817 * If this symbol is really an alias for another, 818 * return that other. 819 * If needed, semantic() is invoked due to resolve forward reference. 820 */ 821 Dsymbol toAlias() 822 { 823 return this; 824 } 825 826 /********************************* 827 * Resolve recursive tuple expansion in eponymous template. 828 */ 829 Dsymbol toAlias2() 830 { 831 return toAlias(); 832 } 833 834 void addMember(Scope* sc, ScopeDsymbol sds) 835 { 836 //printf("Dsymbol::addMember('%s')\n", toChars()); 837 //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); 838 //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); 839 parent = sds; 840 if (isAnonymous()) // no name, so can't add it to symbol table 841 return; 842 843 if (!sds.symtabInsert(this)) // if name is already defined 844 { 845 if (isAliasDeclaration() && !_scope) 846 setScope(sc); 847 Dsymbol s2 = sds.symtabLookup(this,ident); 848 /* https://issues.dlang.org/show_bug.cgi?id=17434 849 * 850 * If we are trying to add an import to the symbol table 851 * that has already been introduced, then keep the one with 852 * larger visibility. This is fine for imports because if 853 * we have multiple imports of the same file, if a single one 854 * is public then the symbol is reachable. 855 */ 856 if (auto i1 = isImport()) 857 { 858 if (auto i2 = s2.isImport()) 859 { 860 if (sc.explicitVisibility && sc.visibility > i2.visibility) 861 sds.symtab.update(this); 862 } 863 } 864 865 // If using C tag/prototype/forward declaration rules 866 if (sc.flags & SCOPE.Cfile && !this.isImport()) 867 { 868 if (handleTagSymbols(*sc, this, s2, sds)) 869 return; 870 if (handleSymbolRedeclarations(*sc, this, s2, sds)) 871 return; 872 873 sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading 874 errors = true; 875 return; 876 } 877 878 if (!s2.overloadInsert(this)) 879 { 880 sds.multiplyDefined(Loc.initial, this, s2); 881 errors = true; 882 } 883 } 884 if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) 885 { 886 if (ident == Id.__sizeof || 887 !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof)) 888 { 889 error("`.%s` property cannot be redefined", ident.toChars()); 890 errors = true; 891 } 892 } 893 } 894 895 /************************************* 896 * Set scope for future semantic analysis so we can 897 * deal better with forward references. 898 */ 899 void setScope(Scope* sc) 900 { 901 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc); 902 if (!sc.nofree) 903 sc.setNoFree(); // may need it even after semantic() finishes 904 _scope = sc; 905 if (sc.depdecl) 906 depdecl = sc.depdecl; 907 if (!userAttribDecl) 908 userAttribDecl = sc.userAttribDecl; 909 } 910 911 void importAll(Scope* sc) 912 { 913 } 914 915 /********************************************* 916 * Search for ident as member of s. 917 * Params: 918 * loc = location to print for error messages 919 * ident = identifier to search for 920 * flags = IgnoreXXXX 921 * Returns: 922 * null if not found 923 */ 924 Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) 925 { 926 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); 927 return null; 928 } 929 930 extern (D) final Dsymbol search_correct(Identifier ident) 931 { 932 /*************************************************** 933 * Search for symbol with correct spelling. 934 */ 935 extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost) 936 { 937 /* If not in the lexer's string table, it certainly isn't in the symbol table. 938 * Doing this first is a lot faster. 939 */ 940 if (!seed.length) 941 return null; 942 Identifier id = Identifier.lookup(seed); 943 if (!id) 944 return null; 945 cost = 0; // all the same cost 946 Dsymbol s = this; 947 Module.clearCache(); 948 return s.search(Loc.initial, id, IgnoreErrors); 949 } 950 951 if (global.gag) 952 return null; // don't do it for speculative compiles; too time consuming 953 // search for exact name first 954 if (auto s = search(Loc.initial, ident, IgnoreErrors)) 955 return s; 956 return speller!symbol_search_fp(ident.toString()); 957 } 958 959 /*************************************** 960 * Search for identifier id as a member of `this`. 961 * `id` may be a template instance. 962 * 963 * Params: 964 * loc = location to print the error messages 965 * sc = the scope where the symbol is located 966 * id = the id of the symbol 967 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` 968 * 969 * Returns: 970 * symbol found, NULL if not 971 */ 972 extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags) 973 { 974 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); 975 Dsymbol s = toAlias(); 976 Dsymbol sm; 977 if (Declaration d = s.isDeclaration()) 978 { 979 if (d.inuse) 980 { 981 .error(loc, "circular reference to `%s`", d.toPrettyChars()); 982 return null; 983 } 984 } 985 switch (id.dyncast()) 986 { 987 case DYNCAST.identifier: 988 sm = s.search(loc, cast(Identifier)id, flags); 989 break; 990 case DYNCAST.dsymbol: 991 { 992 // It's a template instance 993 //printf("\ttemplate instance id\n"); 994 Dsymbol st = cast(Dsymbol)id; 995 TemplateInstance ti = st.isTemplateInstance(); 996 sm = s.search(loc, ti.name); 997 if (!sm) 998 return null; 999 sm = sm.toAlias(); 1000 TemplateDeclaration td = sm.isTemplateDeclaration(); 1001 if (!td) 1002 return null; // error but handled later 1003 ti.tempdecl = td; 1004 if (!ti.semanticRun) 1005 ti.dsymbolSemantic(sc); 1006 sm = ti.toAlias(); 1007 break; 1008 } 1009 case DYNCAST.type: 1010 case DYNCAST.expression: 1011 default: 1012 assert(0); 1013 } 1014 return sm; 1015 } 1016 1017 bool overloadInsert(Dsymbol s) 1018 { 1019 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); 1020 return false; 1021 } 1022 1023 /********************************* 1024 * Returns: 1025 * SIZE_INVALID when the size cannot be determined 1026 */ 1027 uinteger_t size(const ref Loc loc) 1028 { 1029 error("symbol `%s` has no size", toChars()); 1030 return SIZE_INVALID; 1031 } 1032 1033 bool isforwardRef() 1034 { 1035 return false; 1036 } 1037 1038 // is a 'this' required to access the member 1039 inout(AggregateDeclaration) isThis() inout 1040 { 1041 return null; 1042 } 1043 1044 // is Dsymbol exported? 1045 bool isExport() const 1046 { 1047 return false; 1048 } 1049 1050 // is Dsymbol imported? 1051 bool isImportedSymbol() const 1052 { 1053 return false; 1054 } 1055 1056 // is Dsymbol deprecated? 1057 bool isDeprecated() @safe @nogc pure nothrow const 1058 { 1059 return false; 1060 } 1061 1062 bool isOverloadable() const 1063 { 1064 return false; 1065 } 1066 1067 // is this a LabelDsymbol()? 1068 LabelDsymbol isLabel() 1069 { 1070 return null; 1071 } 1072 1073 /// Returns an AggregateDeclaration when toParent() is that. 1074 final inout(AggregateDeclaration) isMember() inout 1075 { 1076 //printf("Dsymbol::isMember() %s\n", toChars()); 1077 auto p = toParent(); 1078 //printf("parent is %s %s\n", p.kind(), p.toChars()); 1079 return p ? p.isAggregateDeclaration() : null; 1080 } 1081 1082 /// Returns an AggregateDeclaration when toParent2() is that. 1083 final inout(AggregateDeclaration) isMember2() inout 1084 { 1085 //printf("Dsymbol::isMember2() '%s'\n", toChars()); 1086 auto p = toParent2(); 1087 //printf("parent is %s %s\n", p.kind(), p.toChars()); 1088 return p ? p.isAggregateDeclaration() : null; 1089 } 1090 1091 /// Returns an AggregateDeclaration when toParentDecl() is that. 1092 final inout(AggregateDeclaration) isMemberDecl() inout 1093 { 1094 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars()); 1095 auto p = toParentDecl(); 1096 //printf("parent is %s %s\n", p.kind(), p.toChars()); 1097 return p ? p.isAggregateDeclaration() : null; 1098 } 1099 1100 /// Returns an AggregateDeclaration when toParentLocal() is that. 1101 final inout(AggregateDeclaration) isMemberLocal() inout 1102 { 1103 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars()); 1104 auto p = toParentLocal(); 1105 //printf("parent is %s %s\n", p.kind(), p.toChars()); 1106 return p ? p.isAggregateDeclaration() : null; 1107 } 1108 1109 // is this a member of a ClassDeclaration? 1110 final ClassDeclaration isClassMember() 1111 { 1112 auto ad = isMember(); 1113 return ad ? ad.isClassDeclaration() : null; 1114 } 1115 1116 // is this a type? 1117 Type getType() 1118 { 1119 return null; 1120 } 1121 1122 // need a 'this' pointer? 1123 bool needThis() 1124 { 1125 return false; 1126 } 1127 1128 /************************************* 1129 */ 1130 Visibility visible() pure nothrow @nogc @safe 1131 { 1132 return Visibility(Visibility.Kind.public_); 1133 } 1134 1135 /************************************** 1136 * Copy the syntax. 1137 * Used for template instantiations. 1138 * If s is NULL, allocate the new object, otherwise fill it in. 1139 */ 1140 Dsymbol syntaxCopy(Dsymbol s) 1141 { 1142 printf("%s %s\n", kind(), toChars()); 1143 assert(0); 1144 } 1145 1146 /************************************** 1147 * Determine if this symbol is only one. 1148 * Returns: 1149 * false, *ps = NULL: There are 2 or more symbols 1150 * true, *ps = NULL: There are zero symbols 1151 * true, *ps = symbol: The one and only one symbol 1152 */ 1153 bool oneMember(Dsymbol* ps, Identifier ident) 1154 { 1155 //printf("Dsymbol::oneMember()\n"); 1156 *ps = this; 1157 return true; 1158 } 1159 1160 /***************************************** 1161 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. 1162 */ 1163 extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident) 1164 { 1165 //printf("Dsymbol::oneMembers() %d\n", members ? members.length : 0); 1166 Dsymbol s = null; 1167 if (!members) 1168 { 1169 *ps = null; 1170 return true; 1171 } 1172 1173 for (size_t i = 0; i < members.length; i++) 1174 { 1175 Dsymbol sx = (*members)[i]; 1176 bool x = sx.oneMember(ps, ident); 1177 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps); 1178 if (!x) 1179 { 1180 //printf("\tfalse 1\n"); 1181 assert(*ps is null); 1182 return false; 1183 } 1184 if (*ps) 1185 { 1186 assert(ident); 1187 if (!(*ps).ident || !(*ps).ident.equals(ident)) 1188 continue; 1189 if (!s) 1190 s = *ps; 1191 else if (s.isOverloadable() && (*ps).isOverloadable()) 1192 { 1193 // keep head of overload set 1194 FuncDeclaration f1 = s.isFuncDeclaration(); 1195 FuncDeclaration f2 = (*ps).isFuncDeclaration(); 1196 if (f1 && f2) 1197 { 1198 assert(!f1.isFuncAliasDeclaration()); 1199 assert(!f2.isFuncAliasDeclaration()); 1200 for (; f1 != f2; f1 = f1.overnext0) 1201 { 1202 if (f1.overnext0 is null) 1203 { 1204 f1.overnext0 = f2; 1205 break; 1206 } 1207 } 1208 } 1209 } 1210 else // more than one symbol 1211 { 1212 *ps = null; 1213 //printf("\tfalse 2\n"); 1214 return false; 1215 } 1216 } 1217 } 1218 *ps = s; // s is the one symbol, null if none 1219 //printf("\ttrue\n"); 1220 return true; 1221 } 1222 1223 void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) 1224 { 1225 } 1226 1227 /***************************************** 1228 * Is Dsymbol a variable that contains pointers? 1229 */ 1230 bool hasPointers() 1231 { 1232 //printf("Dsymbol::hasPointers() %s\n", toChars()); 1233 return false; 1234 } 1235 1236 bool hasStaticCtorOrDtor() 1237 { 1238 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); 1239 return false; 1240 } 1241 1242 void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) 1243 { 1244 } 1245 1246 void checkCtorConstInit() 1247 { 1248 } 1249 1250 /**************************************** 1251 * Add documentation comment to Dsymbol. 1252 * Ignore NULL comments. 1253 */ 1254 void addComment(const(char)* comment) 1255 { 1256 if (!comment || !*comment) 1257 return; 1258 1259 //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars()); 1260 void* h = cast(void*)this; // just the pointer is the key 1261 auto p = h in commentHashTable; 1262 if (!p) 1263 { 1264 commentHashTable[h] = comment; 1265 return; 1266 } 1267 if (strcmp(*p, comment) != 0) 1268 { 1269 // Concatenate the two 1270 *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true); 1271 } 1272 } 1273 1274 /// get documentation comment for this Dsymbol 1275 final const(char)* comment() 1276 { 1277 //printf("getcomment: %p '%s'\n", this, this.toChars()); 1278 if (auto p = cast(void*)this in commentHashTable) 1279 { 1280 //printf("comment: '%s'\n", *p); 1281 return *p; 1282 } 1283 return null; 1284 } 1285 1286 /* Shell around addComment() to avoid disruption for the moment */ 1287 final void comment(const(char)* comment) { addComment(comment); } 1288 1289 private extern (D) __gshared const(char)*[void*] commentHashTable; 1290 1291 1292 /********************************** 1293 * Get ddoc unittest associated with this symbol. 1294 * (only use this with ddoc) 1295 * Returns: ddoc unittest, null if none 1296 */ 1297 final UnitTestDeclaration ddocUnittest() 1298 { 1299 if (auto p = cast(void*)this in ddocUnittestHashTable) 1300 return *p; 1301 return null; 1302 } 1303 1304 /********************************** 1305 * Set ddoc unittest associated with this symbol. 1306 */ 1307 final void ddocUnittest(UnitTestDeclaration utd) 1308 { 1309 ddocUnittestHashTable[cast(void*)this] = utd; 1310 } 1311 1312 private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable; 1313 1314 1315 /**************************************** 1316 * Returns true if this symbol is defined in a non-root module without instantiation. 1317 */ 1318 final bool inNonRoot() 1319 { 1320 Dsymbol s = parent; 1321 for (; s; s = s.toParent()) 1322 { 1323 if (auto ti = s.isTemplateInstance()) 1324 { 1325 return false; 1326 } 1327 if (auto m = s.isModule()) 1328 { 1329 if (!m.isRoot()) 1330 return true; 1331 break; 1332 } 1333 } 1334 return false; 1335 } 1336 1337 /** 1338 * Deinitializes the global state of the compiler. 1339 * 1340 * This can be used to restore the state set by `_init` to its original 1341 * state. 1342 */ 1343 static void deinitialize() 1344 { 1345 commentHashTable = commentHashTable.init; 1346 ddocUnittestHashTable = ddocUnittestHashTable.init; 1347 } 1348 1349 /************ 1350 */ 1351 override void accept(Visitor v) 1352 { 1353 v.visit(this); 1354 } 1355 1356 pure nothrow @safe @nogc: 1357 1358 // Eliminate need for dynamic_cast 1359 inout(Package) isPackage() inout { return null; } 1360 inout(Module) isModule() inout { return null; } 1361 inout(EnumMember) isEnumMember() inout { return null; } 1362 inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; } 1363 inout(TemplateInstance) isTemplateInstance() inout { return null; } 1364 inout(TemplateMixin) isTemplateMixin() inout { return null; } 1365 inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; } 1366 inout(Nspace) isNspace() inout { return null; } 1367 inout(Declaration) isDeclaration() inout { return null; } 1368 inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; } 1369 inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; } 1370 inout(AliasAssign) isAliasAssign() inout { return null; } 1371 inout(ThisDeclaration) isThisDeclaration() inout { return null; } 1372 inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; } 1373 inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; } 1374 inout(TupleDeclaration) isTupleDeclaration() inout { return null; } 1375 inout(AliasDeclaration) isAliasDeclaration() inout { return null; } 1376 inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; } 1377 inout(FuncDeclaration) isFuncDeclaration() inout { return null; } 1378 inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; } 1379 inout(OverDeclaration) isOverDeclaration() inout { return null; } 1380 inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; } 1381 inout(CtorDeclaration) isCtorDeclaration() inout { return null; } 1382 inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; } 1383 inout(DtorDeclaration) isDtorDeclaration() inout { return null; } 1384 inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; } 1385 inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; } 1386 inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; } 1387 inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; } 1388 inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; } 1389 inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; } 1390 inout(NewDeclaration) isNewDeclaration() inout { return null; } 1391 inout(VarDeclaration) isVarDeclaration() inout { return null; } 1392 inout(VersionSymbol) isVersionSymbol() inout { return null; } 1393 inout(DebugSymbol) isDebugSymbol() inout { return null; } 1394 inout(ClassDeclaration) isClassDeclaration() inout { return null; } 1395 inout(StructDeclaration) isStructDeclaration() inout { return null; } 1396 inout(UnionDeclaration) isUnionDeclaration() inout { return null; } 1397 inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; } 1398 inout(ScopeDsymbol) isScopeDsymbol() inout { return null; } 1399 inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; } 1400 inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; } 1401 inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; } 1402 inout(Import) isImport() inout { return null; } 1403 inout(EnumDeclaration) isEnumDeclaration() inout { return null; } 1404 inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; } 1405 inout(AttribDeclaration) isAttribDeclaration() inout { return null; } 1406 inout(AnonDeclaration) isAnonDeclaration() inout { return null; } 1407 inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; } 1408 inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; } 1409 inout(OverloadSet) isOverloadSet() inout { return null; } 1410 inout(MixinDeclaration) isMixinDeclaration() inout { return null; } 1411 inout(StaticAssert) isStaticAssert() inout { return null; } 1412 inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; } 1413 } 1414 1415 /*********************************************************** 1416 * Dsymbol that generates a scope 1417 */ 1418 extern (C++) class ScopeDsymbol : Dsymbol 1419 { 1420 Dsymbols* members; // all Dsymbol's in this scope 1421 DsymbolTable symtab; // members[] sorted into table 1422 uint endlinnum; // the linnumber of the statement after the scope (0 if unknown) 1423 1424 private: 1425 /// symbols whose members have been imported, i.e. imported modules and template mixins 1426 Dsymbols* importedScopes; 1427 Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import 1428 1429 import dmd.root.bitarray; 1430 BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages 1431 1432 public: 1433 final extern (D) this() nothrow 1434 { 1435 } 1436 1437 final extern (D) this(Identifier ident) nothrow 1438 { 1439 super(ident); 1440 } 1441 1442 final extern (D) this(const ref Loc loc, Identifier ident) nothrow 1443 { 1444 super(loc, ident); 1445 } 1446 1447 override ScopeDsymbol syntaxCopy(Dsymbol s) 1448 { 1449 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); 1450 ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident); 1451 sds.comment = comment; 1452 sds.members = arraySyntaxCopy(members); 1453 sds.endlinnum = endlinnum; 1454 return sds; 1455 } 1456 1457 /***************************************** 1458 * This function is #1 on the list of functions that eat cpu time. 1459 * Be very, very careful about slowing it down. 1460 */ 1461 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 1462 { 1463 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); 1464 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; 1465 1466 // Look in symbols declared in this module 1467 if (symtab && !(flags & SearchImportsOnly)) 1468 { 1469 //printf(" look in locals\n"); 1470 auto s1 = symtab.lookup(ident); 1471 if (s1) 1472 { 1473 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); 1474 return s1; 1475 } 1476 } 1477 //printf(" not found in locals\n"); 1478 1479 // Look in imported scopes 1480 if (!importedScopes) 1481 return null; 1482 1483 //printf(" look in imports\n"); 1484 Dsymbol s = null; 1485 OverloadSet a = null; 1486 // Look in imported modules 1487 for (size_t i = 0; i < importedScopes.length; i++) 1488 { 1489 // If private import, don't search it 1490 if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_) 1491 continue; 1492 int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches 1493 Dsymbol ss = (*importedScopes)[i]; 1494 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); 1495 1496 if (ss.isModule()) 1497 { 1498 if (flags & SearchLocalsOnly) 1499 continue; 1500 } 1501 else // mixin template 1502 { 1503 if (flags & SearchImportsOnly) 1504 continue; 1505 1506 sflags |= SearchLocalsOnly; 1507 } 1508 1509 /* Don't find private members if ss is a module 1510 */ 1511 Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); 1512 import dmd.access : symbolIsVisible; 1513 if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)) 1514 continue; 1515 if (!s) 1516 { 1517 s = s2; 1518 if (s && s.isOverloadSet()) 1519 a = mergeOverloadSet(ident, a, s); 1520 } 1521 else if (s2 && s != s2) 1522 { 1523 if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) 1524 { 1525 /* After following aliases, we found the same 1526 * symbol, so it's not an ambiguity. But if one 1527 * alias is deprecated or less accessible, prefer 1528 * the other. 1529 */ 1530 if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none) 1531 s = s2; 1532 } 1533 else 1534 { 1535 /* Two imports of the same module should be regarded as 1536 * the same. 1537 */ 1538 Import i1 = s.isImport(); 1539 Import i2 = s2.isImport(); 1540 if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) 1541 { 1542 /* https://issues.dlang.org/show_bug.cgi?id=8668 1543 * Public selective import adds AliasDeclaration in module. 1544 * To make an overload set, resolve aliases in here and 1545 * get actual overload roots which accessible via s and s2. 1546 */ 1547 s = s.toAlias(); 1548 s2 = s2.toAlias(); 1549 /* If both s2 and s are overloadable (though we only 1550 * need to check s once) 1551 */ 1552 1553 auto so2 = s2.isOverloadSet(); 1554 if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) 1555 { 1556 if (symbolIsVisible(this, s2)) 1557 { 1558 a = mergeOverloadSet(ident, a, s2); 1559 } 1560 if (!symbolIsVisible(this, s)) 1561 s = s2; 1562 continue; 1563 } 1564 1565 /* Two different overflow sets can have the same members 1566 * https://issues.dlang.org/show_bug.cgi?id=16709 1567 */ 1568 auto so = s.isOverloadSet(); 1569 if (so && so2) 1570 { 1571 if (so.a.length == so2.a.length) 1572 { 1573 foreach (j; 0 .. so.a.length) 1574 { 1575 if (so.a[j] !is so2.a[j]) 1576 goto L1; 1577 } 1578 continue; // the same 1579 L1: 1580 { } // different 1581 } 1582 } 1583 1584 if (flags & IgnoreAmbiguous) // if return NULL on ambiguity 1585 return null; 1586 1587 /* If two imports from C import files, pick first one, as C has global name space 1588 */ 1589 if (s.isCsymbol() && s2.isCsymbol()) 1590 continue; 1591 1592 if (!(flags & IgnoreErrors)) 1593 ScopeDsymbol.multiplyDefined(loc, s, s2); 1594 break; 1595 } 1596 } 1597 } 1598 } 1599 if (s) 1600 { 1601 /* Build special symbol if we had multiple finds 1602 */ 1603 if (a) 1604 { 1605 if (!s.isOverloadSet()) 1606 a = mergeOverloadSet(ident, a, s); 1607 s = a; 1608 } 1609 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); 1610 return s; 1611 } 1612 //printf(" not found in imports\n"); 1613 return null; 1614 } 1615 1616 extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) 1617 { 1618 if (!os) 1619 { 1620 os = new OverloadSet(ident); 1621 os.parent = this; 1622 } 1623 if (OverloadSet os2 = s.isOverloadSet()) 1624 { 1625 // Merge the cross-module overload set 'os2' into 'os' 1626 if (os.a.length == 0) 1627 { 1628 os.a.setDim(os2.a.length); 1629 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.length); 1630 } 1631 else 1632 { 1633 for (size_t i = 0; i < os2.a.length; i++) 1634 { 1635 os = mergeOverloadSet(ident, os, os2.a[i]); 1636 } 1637 } 1638 } 1639 else 1640 { 1641 assert(s.isOverloadable()); 1642 /* Don't add to os[] if s is alias of previous sym 1643 */ 1644 for (size_t j = 0; j < os.a.length; j++) 1645 { 1646 Dsymbol s2 = os.a[j]; 1647 if (s.toAlias() == s2.toAlias()) 1648 { 1649 if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none)) 1650 { 1651 os.a[j] = s; 1652 } 1653 goto Lcontinue; 1654 } 1655 } 1656 os.push(s); 1657 Lcontinue: 1658 } 1659 return os; 1660 } 1661 1662 void importScope(Dsymbol s, Visibility visibility) nothrow 1663 { 1664 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility); 1665 // No circular or redundant import's 1666 if (s != this) 1667 { 1668 if (!importedScopes) 1669 importedScopes = new Dsymbols(); 1670 else 1671 { 1672 for (size_t i = 0; i < importedScopes.length; i++) 1673 { 1674 Dsymbol ss = (*importedScopes)[i]; 1675 if (ss == s) // if already imported 1676 { 1677 if (visibility.kind > visibilities[i]) 1678 visibilities[i] = visibility.kind; // upgrade access 1679 return; 1680 } 1681 } 1682 } 1683 importedScopes.push(s); 1684 visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.length * (visibilities[0]).sizeof); 1685 visibilities[importedScopes.length - 1] = visibility.kind; 1686 } 1687 } 1688 1689 1690 /***************************************** 1691 * Returns: the symbols whose members have been imported, i.e. imported modules 1692 * and template mixins. 1693 * 1694 * See_Also: importScope 1695 */ 1696 extern (D) final Dsymbols* getImportedScopes() nothrow @nogc @safe pure 1697 { 1698 return importedScopes; 1699 } 1700 1701 /***************************************** 1702 * Returns: the array of visibilities associated with each imported scope. The 1703 * length of the array matches the imported scopes array. 1704 * 1705 * See_Also: getImportedScopes 1706 */ 1707 extern (D) final Visibility.Kind[] getImportVisibilities() nothrow @nogc @safe pure 1708 { 1709 if (!importedScopes) 1710 return null; 1711 1712 return (() @trusted => visibilities[0 .. importedScopes.length])(); 1713 } 1714 1715 extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow 1716 { 1717 auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages; 1718 if (pary.length <= p.tag) 1719 pary.length = p.tag + 1; 1720 (*pary)[p.tag] = true; 1721 } 1722 1723 bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow 1724 { 1725 if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] || 1726 visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag]) 1727 return true; 1728 foreach (i, ss; importedScopes ? (*importedScopes)[] : null) 1729 { 1730 // only search visible scopes && imported modules should ignore private imports 1731 if (visibility.kind <= visibilities[i] && 1732 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports)) 1733 return true; 1734 } 1735 return false; 1736 } 1737 1738 override final bool isforwardRef() nothrow 1739 { 1740 return (members is null); 1741 } 1742 1743 static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2) 1744 { 1745 version (none) 1746 { 1747 printf("ScopeDsymbol::multiplyDefined()\n"); 1748 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : ""); 1749 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : ""); 1750 } 1751 if (loc.isValid()) 1752 { 1753 .error(loc, "`%s` matches conflicting symbols:", s1.ident.toChars()); 1754 errorSupplemental(s1.loc, "%s `%s`", s1.kind(), s1.toPrettyChars()); 1755 errorSupplemental(s2.loc, "%s `%s`", s2.kind(), s2.toPrettyChars()); 1756 1757 static if (0) 1758 { 1759 if (auto so = s1.isOverloadSet()) 1760 { 1761 printf("first %p:\n", so); 1762 foreach (s; so.a[]) 1763 { 1764 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars()); 1765 } 1766 } 1767 if (auto so = s2.isOverloadSet()) 1768 { 1769 printf("second %p:\n", so); 1770 foreach (s; so.a[]) 1771 { 1772 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars()); 1773 } 1774 } 1775 } 1776 } 1777 else 1778 { 1779 s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars()); 1780 } 1781 } 1782 1783 override const(char)* kind() const 1784 { 1785 return "ScopeDsymbol"; 1786 } 1787 1788 /******************************************* 1789 * Look for member of the form: 1790 * const(MemberInfo)[] getMembers(string); 1791 * Returns NULL if not found 1792 */ 1793 final FuncDeclaration findGetMembers() 1794 { 1795 Dsymbol s = search_function(this, Id.getmembers); 1796 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; 1797 version (none) 1798 { 1799 // Finish 1800 __gshared TypeFunction tfgetmembers; 1801 if (!tfgetmembers) 1802 { 1803 Scope sc; 1804 auto parameters = new Parameters(); 1805 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); 1806 parameters.push(p); 1807 Type tret = null; 1808 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d); 1809 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc); 1810 } 1811 if (fdx) 1812 fdx = fdx.overloadExactMatch(tfgetmembers); 1813 } 1814 if (fdx && fdx.isVirtual()) 1815 fdx = null; 1816 return fdx; 1817 } 1818 1819 /******************************** 1820 * Insert Dsymbol in table. 1821 * Params: 1822 * s = symbol to add 1823 * Returns: 1824 * null if already in table, `s` if inserted 1825 */ 1826 Dsymbol symtabInsert(Dsymbol s) nothrow 1827 { 1828 return symtab.insert(s); 1829 } 1830 1831 /**************************************** 1832 * Look up identifier in symbol table. 1833 * Params: 1834 * s = symbol 1835 * id = identifier to look up 1836 * Returns: 1837 * Dsymbol if found, null if not 1838 */ 1839 Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow 1840 { 1841 return symtab.lookup(id); 1842 } 1843 1844 /**************************************** 1845 * Return true if any of the members are static ctors or static dtors, or if 1846 * any members have members that are. 1847 */ 1848 override bool hasStaticCtorOrDtor() 1849 { 1850 if (members) 1851 { 1852 for (size_t i = 0; i < members.length; i++) 1853 { 1854 Dsymbol member = (*members)[i]; 1855 if (member.hasStaticCtorOrDtor()) 1856 return true; 1857 } 1858 } 1859 return false; 1860 } 1861 1862 extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s); 1863 1864 /*************************************** 1865 * Expands attribute declarations in members in depth first 1866 * order. Calls dg(size_t symidx, Dsymbol *sym) for each 1867 * member. 1868 * If dg returns !=0, stops and returns that value else returns 0. 1869 * Use this function to avoid the O(N + N^2/2) complexity of 1870 * calculating dim and calling N times getNth. 1871 * Returns: 1872 * last value returned by dg() 1873 */ 1874 extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) 1875 { 1876 assert(dg); 1877 if (!members) 1878 return 0; 1879 size_t n = pn ? *pn : 0; // take over index 1880 int result = 0; 1881 foreach (size_t i; 0 .. members.length) 1882 { 1883 Dsymbol s = (*members)[i]; 1884 if (AttribDeclaration a = s.isAttribDeclaration()) 1885 result = _foreach(sc, a.include(sc), dg, &n); 1886 else if (TemplateMixin tm = s.isTemplateMixin()) 1887 result = _foreach(sc, tm.members, dg, &n); 1888 else if (s.isTemplateInstance()) 1889 { 1890 } 1891 else if (s.isUnitTestDeclaration()) 1892 { 1893 } 1894 else 1895 result = dg(n++, s); 1896 if (result) 1897 break; 1898 } 1899 if (pn) 1900 *pn = n; // update index 1901 return result; 1902 } 1903 1904 override final inout(ScopeDsymbol) isScopeDsymbol() inout 1905 { 1906 return this; 1907 } 1908 1909 override void accept(Visitor v) 1910 { 1911 v.visit(this); 1912 } 1913 } 1914 1915 /*********************************************************** 1916 * With statement scope 1917 */ 1918 extern (C++) final class WithScopeSymbol : ScopeDsymbol 1919 { 1920 WithStatement withstate; 1921 1922 extern (D) this(WithStatement withstate) nothrow 1923 { 1924 this.withstate = withstate; 1925 } 1926 1927 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 1928 { 1929 //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); 1930 if (flags & SearchImportsOnly) 1931 return null; 1932 // Acts as proxy to the with class declaration 1933 Dsymbol s = null; 1934 Expression eold = null; 1935 for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true)) 1936 { 1937 if (e.op == EXP.scope_) 1938 { 1939 s = (cast(ScopeExp)e).sds; 1940 } 1941 else if (e.op == EXP.type) 1942 { 1943 s = e.type.toDsymbol(null); 1944 } 1945 else 1946 { 1947 Type t = e.type.toBasetype(); 1948 s = t.toDsymbol(null); 1949 } 1950 if (s) 1951 { 1952 s = s.search(loc, ident, flags); 1953 if (s) 1954 return s; 1955 } 1956 eold = e; 1957 } 1958 return null; 1959 } 1960 1961 override inout(WithScopeSymbol) isWithScopeSymbol() inout 1962 { 1963 return this; 1964 } 1965 1966 override void accept(Visitor v) 1967 { 1968 v.visit(this); 1969 } 1970 } 1971 1972 /*********************************************************** 1973 * Array Index/Slice scope 1974 */ 1975 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol 1976 { 1977 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration. 1978 // Discriminated using DYNCAST and, for expressions, also EXP 1979 private RootObject arrayContent; 1980 Scope* sc; 1981 1982 extern (D) this(Scope* sc, Expression exp) nothrow 1983 { 1984 super(exp.loc, null); 1985 assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array); 1986 this.sc = sc; 1987 this.arrayContent = exp; 1988 } 1989 1990 extern (D) this(Scope* sc, TypeTuple type) nothrow 1991 { 1992 this.sc = sc; 1993 this.arrayContent = type; 1994 } 1995 1996 extern (D) this(Scope* sc, TupleDeclaration td) nothrow 1997 { 1998 this.sc = sc; 1999 this.arrayContent = td; 2000 } 2001 2002 /// This override is used to solve `$` 2003 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) 2004 { 2005 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); 2006 if (ident != Id.dollar) 2007 return null; 2008 2009 VarDeclaration* pvar; 2010 Expression ce; 2011 2012 static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc) 2013 { 2014 2015 /* $ gives the number of type entries in the type tuple 2016 */ 2017 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); 2018 Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t); 2019 v._init = new ExpInitializer(Loc.initial, e); 2020 v.storage_class |= STC.temp | STC.static_ | STC.const_; 2021 v.dsymbolSemantic(sc); 2022 return v; 2023 } 2024 2025 const DYNCAST kind = arrayContent.dyncast(); 2026 switch (kind) with (DYNCAST) 2027 { 2028 case dsymbol: 2029 TupleDeclaration td = cast(TupleDeclaration) arrayContent; 2030 /* $ gives the number of elements in the tuple 2031 */ 2032 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); 2033 Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t); 2034 v._init = new ExpInitializer(Loc.initial, e); 2035 v.storage_class |= STC.temp | STC.static_ | STC.const_; 2036 v.dsymbolSemantic(sc); 2037 return v; 2038 case type: 2039 return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc); 2040 default: 2041 break; 2042 } 2043 Expression exp = cast(Expression) arrayContent; 2044 if (auto ie = exp.isIndexExp()) 2045 { 2046 /* array[index] where index is some function of $ 2047 */ 2048 pvar = &ie.lengthVar; 2049 ce = ie.e1; 2050 } 2051 else if (auto se = exp.isSliceExp()) 2052 { 2053 /* array[lwr .. upr] where lwr or upr is some function of $ 2054 */ 2055 pvar = &se.lengthVar; 2056 ce = se.e1; 2057 } 2058 else if (auto ae = exp.isArrayExp()) 2059 { 2060 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ 2061 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) 2062 */ 2063 pvar = &ae.lengthVar; 2064 ce = ae.e1; 2065 } 2066 else 2067 { 2068 /* Didn't find $, look in enclosing scope(s). 2069 */ 2070 return null; 2071 } 2072 ce = ce.lastComma(); 2073 /* If we are indexing into an array that is really a type 2074 * tuple, rewrite this as an index into a type tuple and 2075 * try again. 2076 */ 2077 if (auto te = ce.isTypeExp()) 2078 { 2079 if (auto ttp = te.type.isTypeTuple()) 2080 return dollarFromTypeTuple(loc, ttp, sc); 2081 } 2082 /* *pvar is lazily initialized, so if we refer to $ 2083 * multiple times, it gets set only once. 2084 */ 2085 if (!*pvar) // if not already initialized 2086 { 2087 /* Create variable v and set it to the value of $ 2088 */ 2089 VarDeclaration v; 2090 Type t; 2091 if (auto tupexp = ce.isTupleExp()) 2092 { 2093 /* It is for an expression tuple, so the 2094 * length will be a const. 2095 */ 2096 Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t); 2097 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); 2098 v.storage_class |= STC.temp | STC.static_ | STC.const_; 2099 } 2100 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) 2101 { 2102 // Look for opDollar 2103 assert(exp.op == EXP.array || exp.op == EXP.slice); 2104 AggregateDeclaration ad = isAggregate(t); 2105 assert(ad); 2106 Dsymbol s = ad.search(loc, Id.opDollar); 2107 if (!s) // no dollar exists -- search in higher scope 2108 return null; 2109 s = s.toAlias(); 2110 Expression e = null; 2111 // Check for multi-dimensional opDollar(dim) template. 2112 if (TemplateDeclaration td = s.isTemplateDeclaration()) 2113 { 2114 dinteger_t dim = 0; 2115 if (exp.op == EXP.array) 2116 { 2117 dim = (cast(ArrayExp)exp).currentDimension; 2118 } 2119 else if (exp.op == EXP.slice) 2120 { 2121 dim = 0; // slices are currently always one-dimensional 2122 } 2123 else 2124 { 2125 assert(0); 2126 } 2127 auto tiargs = new Objects(); 2128 Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); 2129 edim = edim.expressionSemantic(sc); 2130 tiargs.push(edim); 2131 e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); 2132 } 2133 else 2134 { 2135 /* opDollar exists, but it's not a template. 2136 * This is acceptable ONLY for single-dimension indexing. 2137 * Note that it's impossible to have both template & function opDollar, 2138 * because both take no arguments. 2139 */ 2140 if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.length != 1) 2141 { 2142 exp.error("`%s` only defines opDollar for one dimension", ad.toChars()); 2143 return null; 2144 } 2145 Declaration d = s.isDeclaration(); 2146 assert(d); 2147 e = new DotVarExp(loc, ce, d); 2148 } 2149 e = e.expressionSemantic(sc); 2150 if (!e.type) 2151 exp.error("`%s` has no value", e.toChars()); 2152 t = e.type.toBasetype(); 2153 if (t && t.ty == Tfunction) 2154 e = new CallExp(e.loc, e); 2155 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); 2156 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; 2157 } 2158 else 2159 { 2160 /* For arrays, $ will either be a compile-time constant 2161 * (in which case its value in set during constant-folding), 2162 * or a variable (in which case an expression is created in 2163 * toir.c). 2164 */ 2165 2166 // https://issues.dlang.org/show_bug.cgi?id=16213 2167 // For static arrays $ is known at compile time, 2168 // so declare it as a manifest constant. 2169 auto tsa = ce.type ? ce.type.isTypeSArray() : null; 2170 if (tsa) 2171 { 2172 auto e = new ExpInitializer(loc, tsa.dim); 2173 v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); 2174 } 2175 else 2176 { 2177 auto e = new VoidInitializer(Loc.initial); 2178 e.type = Type.tsize_t; 2179 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); 2180 v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable 2181 } 2182 } 2183 *pvar = v; 2184 } 2185 (*pvar).dsymbolSemantic(sc); 2186 return (*pvar); 2187 } 2188 2189 override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout 2190 { 2191 return this; 2192 } 2193 2194 override void accept(Visitor v) 2195 { 2196 v.visit(this); 2197 } 2198 } 2199 2200 /*********************************************************** 2201 * Overload Sets 2202 */ 2203 extern (C++) final class OverloadSet : Dsymbol 2204 { 2205 Dsymbols a; // array of Dsymbols 2206 2207 extern (D) this(Identifier ident, OverloadSet os = null) nothrow 2208 { 2209 super(ident); 2210 if (os) 2211 { 2212 a.pushSlice(os.a[]); 2213 } 2214 } 2215 2216 void push(Dsymbol s) nothrow 2217 { 2218 a.push(s); 2219 } 2220 2221 override inout(OverloadSet) isOverloadSet() inout 2222 { 2223 return this; 2224 } 2225 2226 override const(char)* kind() const 2227 { 2228 return "overloadset"; 2229 } 2230 2231 override void accept(Visitor v) 2232 { 2233 v.visit(this); 2234 } 2235 } 2236 2237 /*********************************************************** 2238 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and 2239 * ForwardingScopeDeclaration to forward symbol insertions to another 2240 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more 2241 * details. 2242 */ 2243 extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol 2244 { 2245 extern (D) this() nothrow 2246 { 2247 super(); 2248 } 2249 2250 override Dsymbol symtabInsert(Dsymbol s) nothrow 2251 { 2252 if (auto d = s.isDeclaration()) 2253 { 2254 if (d.storage_class & STC.local) 2255 { 2256 // Symbols with storage class STC.local are not 2257 // forwarded, but stored in the local symbol 2258 // table. (Those are the `static foreach` variables.) 2259 if (!symtab) 2260 { 2261 symtab = new DsymbolTable(); 2262 } 2263 return super.symtabInsert(s); // insert locally 2264 } 2265 } 2266 auto forward = parent.isScopeDsymbol(); 2267 assert(forward); 2268 if (!forward.symtab) 2269 { 2270 forward.symtab = new DsymbolTable(); 2271 } 2272 // Non-STC.local symbols are forwarded to `forward`. 2273 return forward.symtabInsert(s); 2274 } 2275 2276 /************************ 2277 * This override handles the following two cases: 2278 * static foreach (i, i; [0]) { ... } 2279 * and 2280 * static foreach (i; [0]) { enum i = 2; } 2281 */ 2282 override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow 2283 { 2284 // correctly diagnose clashing foreach loop variables. 2285 if (auto d = s.isDeclaration()) 2286 { 2287 if (d.storage_class & STC.local) 2288 { 2289 if (!symtab) 2290 { 2291 symtab = new DsymbolTable(); 2292 } 2293 return super.symtabLookup(s,id); 2294 } 2295 } 2296 // Declarations within `static foreach` do not clash with 2297 // `static foreach` loop variables. 2298 auto forward = parent.isScopeDsymbol(); 2299 assert(forward); 2300 if (!forward.symtab) 2301 { 2302 forward.symtab = new DsymbolTable(); 2303 } 2304 return forward.symtabLookup(s,id); 2305 } 2306 2307 override void importScope(Dsymbol s, Visibility visibility) 2308 { 2309 auto forward = parent.isScopeDsymbol(); 2310 assert(forward); 2311 forward.importScope(s, visibility); 2312 } 2313 2314 override const(char)* kind()const{ return "local scope"; } 2315 2316 override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow 2317 { 2318 return this; 2319 } 2320 2321 } 2322 2323 /** 2324 * Class that holds an expression in a Dsymbol wrapper. 2325 * This is not an AST node, but a class used to pass 2326 * an expression as a function parameter of type Dsymbol. 2327 */ 2328 extern (C++) final class ExpressionDsymbol : Dsymbol 2329 { 2330 Expression exp; 2331 this(Expression exp) nothrow 2332 { 2333 super(); 2334 this.exp = exp; 2335 } 2336 2337 override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow 2338 { 2339 return this; 2340 } 2341 } 2342 2343 /********************************************** 2344 * Encapsulate assigning to an alias: 2345 * `identifier = type;` 2346 * `identifier = symbol;` 2347 * where `identifier` is an AliasDeclaration in scope. 2348 */ 2349 extern (C++) final class AliasAssign : Dsymbol 2350 { 2351 Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous 2352 Type type; /// replace previous RHS of AliasDeclaration with `type` 2353 Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym` 2354 /// only one of type and aliassym can be != null 2355 2356 extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow 2357 { 2358 super(loc, null); 2359 this.ident = ident; 2360 this.type = type; 2361 this.aliassym = aliassym; 2362 } 2363 2364 override AliasAssign syntaxCopy(Dsymbol s) 2365 { 2366 assert(!s); 2367 AliasAssign aa = new AliasAssign(loc, ident, 2368 type ? type.syntaxCopy() : null, 2369 aliassym ? aliassym.syntaxCopy(null) : null); 2370 return aa; 2371 } 2372 2373 override inout(AliasAssign) isAliasAssign() inout 2374 { 2375 return this; 2376 } 2377 2378 override const(char)* kind() const 2379 { 2380 return "alias assignment"; 2381 } 2382 2383 override void accept(Visitor v) 2384 { 2385 v.visit(this); 2386 } 2387 } 2388 2389 /*********************************************************** 2390 * Table of Dsymbol's 2391 */ 2392 extern (C++) final class DsymbolTable : RootObject 2393 { 2394 AssocArray!(Identifier, Dsymbol) tab; 2395 2396 nothrow: 2397 2398 /*************************** 2399 * Look up Identifier in symbol table 2400 * Params: 2401 * ident = identifer to look up 2402 * Returns: 2403 * Dsymbol if found, null if not 2404 */ 2405 Dsymbol lookup(const Identifier ident) 2406 { 2407 //printf("DsymbolTable::lookup(%s)\n", ident.toChars()); 2408 return tab[ident]; 2409 } 2410 2411 /********** 2412 * Replace existing symbol in symbol table with `s`. 2413 * If it's not there, add it. 2414 * Params: 2415 * s = replacement symbol with same identifier 2416 */ 2417 void update(Dsymbol s) 2418 { 2419 *tab.getLvalue(s.ident) = s; 2420 } 2421 2422 /************************** 2423 * Insert Dsymbol in table. 2424 * Params: 2425 * s = symbol to add 2426 * Returns: 2427 * null if already in table, `s` if inserted 2428 */ 2429 Dsymbol insert(Dsymbol s) 2430 { 2431 return insert(s.ident, s); 2432 } 2433 2434 /************************** 2435 * Insert Dsymbol in table. 2436 * Params: 2437 * ident = identifier to serve as index 2438 * s = symbol to add 2439 * Returns: 2440 * null if already in table, `s` if inserted 2441 */ 2442 Dsymbol insert(const Identifier ident, Dsymbol s) 2443 { 2444 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars()); 2445 Dsymbol* ps = tab.getLvalue(ident); 2446 if (*ps) 2447 return null; // already in table 2448 *ps = s; 2449 return s; 2450 } 2451 2452 /***************** 2453 * Returns: 2454 * number of symbols in symbol table 2455 */ 2456 size_t length() const pure 2457 { 2458 return tab.length; 2459 } 2460 } 2461 2462 /********************************************** 2463 * ImportC tag symbols sit in a parallel symbol table, 2464 * so that this C code works: 2465 * --- 2466 * struct S { a; }; 2467 * int S; 2468 * struct S s; 2469 * --- 2470 * But there are relatively few such tag symbols, so that would be 2471 * a waste of memory and complexity. An additional problem is we'd like the D side 2472 * to find the tag symbols with ordinary lookup, not lookup in both 2473 * tables, if the tag symbol is not conflicting with an ordinary symbol. 2474 * The solution is to put the tag symbols that conflict into an associative 2475 * array, indexed by the address of the ordinary symbol that conflicts with it. 2476 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration. 2477 * A side effect of our approach is that D code cannot access a tag symbol that is 2478 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody 2479 * has mentioned it when importing C headers. If someone wants to do it, 2480 * too bad so sad. Change the C code. 2481 * This function fixes up the symbol table when faced with adding a new symbol 2482 * `s` when there is an existing symbol `s2` with the same name. 2483 * C also allows forward and prototype declarations of tag symbols, 2484 * this function merges those. 2485 * Params: 2486 * sc = context 2487 * s = symbol to add to symbol table 2488 * s2 = existing declaration 2489 * sds = symbol table 2490 * Returns: 2491 * if s and s2 are successfully put in symbol table then return the merged symbol, 2492 * null if they conflict 2493 */ 2494 Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) 2495 { 2496 enum log = false; 2497 if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2); 2498 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars()); 2499 auto sd = s.isScopeDsymbol(); // new declaration 2500 auto sd2 = s2.isScopeDsymbol(); // existing declaration 2501 2502 static if (log) void print(EnumDeclaration sd) 2503 { 2504 printf("members: %p\n", sd.members); 2505 printf("symtab: %p\n", sd.symtab); 2506 printf("endlinnum: %d\n", sd.endlinnum); 2507 printf("type: %s\n", sd.type.toChars()); 2508 printf("memtype: %s\n", sd.memtype.toChars()); 2509 } 2510 2511 if (!sd2) 2512 { 2513 /* Look in tag table 2514 */ 2515 if (log) printf(" look in tag table\n"); 2516 if (auto p = cast(void*)s2 in sc._module.tagSymTab) 2517 { 2518 Dsymbol s2tag = *p; 2519 sd2 = s2tag.isScopeDsymbol(); 2520 assert(sd2); // only tags allowed in tag symbol table 2521 } 2522 } 2523 2524 if (sd && sd2) // `s` is a tag, `sd2` is the same tag 2525 { 2526 if (log) printf(" tag is already defined\n"); 2527 2528 if (sd.kind() != sd2.kind()) // being enum/struct/union must match 2529 return null; // conflict 2530 2531 /* Not a redeclaration if one is a forward declaration. 2532 * Move members to the first declared type, which is sd2. 2533 */ 2534 if (sd2.members) 2535 { 2536 if (!sd.members) 2537 return sd2; // ignore the sd redeclaration 2538 } 2539 else if (sd.members) 2540 { 2541 sd2.members = sd.members; // transfer definition to sd2 2542 sd.members = null; 2543 if (auto ed2 = sd2.isEnumDeclaration()) 2544 { 2545 auto ed = sd.isEnumDeclaration(); 2546 if (ed.memtype != ed2.memtype) 2547 return null; // conflict 2548 2549 // transfer ed's members to sd2 2550 ed2.members.foreachDsymbol( (s) 2551 { 2552 if (auto em = s.isEnumMember()) 2553 em.ed = ed2; 2554 }); 2555 2556 ed2.type = ed.type; 2557 ed2.memtype = ed.memtype; 2558 ed2.added = false; 2559 } 2560 return sd2; 2561 } 2562 else 2563 return sd2; // ignore redeclaration 2564 } 2565 else if (sd) // `s` is a tag, `s2` is not 2566 { 2567 if (log) printf(" s is tag, s2 is not\n"); 2568 /* add `s` as tag indexed by s2 2569 */ 2570 sc._module.tagSymTab[cast(void*)s2] = s; 2571 return s; 2572 } 2573 else if (s2 is sd2) // `s2` is a tag, `s` is not 2574 { 2575 if (log) printf(" s2 is tag, s is not\n"); 2576 /* replace `s2` in symbol table with `s`, 2577 * then add `s2` as tag indexed by `s` 2578 */ 2579 sds.symtab.update(s); 2580 sc._module.tagSymTab[cast(void*)s] = s2; 2581 return s; 2582 } 2583 // neither s2 nor s is a tag 2584 if (log) printf(" collision\n"); 2585 return null; 2586 } 2587 2588 2589 /********************************************** 2590 * ImportC allows redeclarations of C variables, functions and typedefs. 2591 * extern int x; 2592 * int x = 3; 2593 * and: 2594 * extern void f(); 2595 * void f() { } 2596 * Attempt to merge them. 2597 * Params: 2598 * sc = context 2599 * s = symbol to add to symbol table 2600 * s2 = existing declaration 2601 * sds = symbol table 2602 * Returns: 2603 * if s and s2 are successfully put in symbol table then return the merged symbol, 2604 * null if they conflict 2605 */ 2606 Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) 2607 { 2608 enum log = false; 2609 if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars()); 2610 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars()); 2611 2612 static Dsymbol collision() 2613 { 2614 if (log) printf(" collision\n"); 2615 return null; 2616 } 2617 /* 2618 Handle merging declarations with asm("foo") and their definitions 2619 */ 2620 static void mangleWrangle(Declaration oldDecl, Declaration newDecl) 2621 { 2622 if (oldDecl && newDecl) 2623 { 2624 newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null; 2625 } 2626 } 2627 2628 auto vd = s.isVarDeclaration(); // new declaration 2629 auto vd2 = s2.isVarDeclaration(); // existing declaration 2630 2631 if (vd && vd.isCmacro()) 2632 return vd2; 2633 2634 assert(!(vd2 && vd2.isCmacro())); 2635 2636 if (vd && vd2) 2637 { 2638 /* if one is `static` and the other isn't, the result is undefined 2639 * behavior, C11 6.2.2.7 2640 */ 2641 if ((vd.storage_class ^ vd2.storage_class) & STC.static_) 2642 return collision(); 2643 2644 const i1 = vd._init && ! vd._init.isVoidInitializer(); 2645 const i2 = vd2._init && !vd2._init.isVoidInitializer(); 2646 2647 if (i1 && i2) 2648 return collision(); // can't both have initializers 2649 2650 mangleWrangle(vd2, vd); 2651 2652 if (i1) // vd is the definition 2653 { 2654 vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it 2655 sds.symtab.update(vd); // replace vd2 with the definition 2656 return vd; 2657 } 2658 2659 /* BUG: the types should match, which needs semantic() to be run on it 2660 * extern int x; 2661 * int x; // match 2662 * typedef int INT; 2663 * INT x; // match 2664 * long x; // collision 2665 * We incorrectly ignore these collisions 2666 */ 2667 return vd2; 2668 } 2669 2670 auto fd = s.isFuncDeclaration(); // new declaration 2671 auto fd2 = s2.isFuncDeclaration(); // existing declaration 2672 if (fd && fd2) 2673 { 2674 /* if one is `static` and the other isn't, the result is undefined 2675 * behavior, C11 6.2.2.7 2676 * However, match what gcc allows: 2677 * static int sun1(); int sun1() { return 0; } 2678 * and: 2679 * static int sun2() { return 0; } int sun2(); 2680 * Both produce a static function. 2681 * 2682 * Both of these should fail: 2683 * int sun3(); static int sun3() { return 0; } 2684 * and: 2685 * int sun4() { return 0; } static int sun4(); 2686 */ 2687 // if adding `static` 2688 if ( fd.storage_class & STC.static_ && 2689 !(fd2.storage_class & STC.static_)) 2690 { 2691 return collision(); 2692 } 2693 2694 if (fd.fbody && fd2.fbody) 2695 return collision(); // can't both have bodies 2696 2697 mangleWrangle(fd2, fd); 2698 2699 if (fd.fbody) // fd is the definition 2700 { 2701 if (log) printf(" replace existing with new\n"); 2702 sds.symtab.update(fd); // replace fd2 in symbol table with fd 2703 fd.overnext = fd2; 2704 2705 /* If fd2 is covering a tag symbol, then fd has to cover the same one 2706 */ 2707 auto ps = cast(void*)fd2 in sc._module.tagSymTab; 2708 if (ps) 2709 sc._module.tagSymTab[cast(void*)fd] = *ps; 2710 2711 return fd; 2712 } 2713 2714 /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it. 2715 * FuncDeclaration::semantic() detects this, but it relies on .overnext being set. 2716 */ 2717 fd2.overloadInsert(fd); 2718 2719 return fd2; 2720 } 2721 2722 auto td = s.isAliasDeclaration(); // new declaration 2723 auto td2 = s2.isAliasDeclaration(); // existing declaration 2724 if (td && td2) 2725 { 2726 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it. 2727 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set. 2728 */ 2729 return td2; 2730 } 2731 2732 return collision(); 2733 }