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