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