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