1 2/* Compiler implementation of the D programming language 3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved 4 * written by Walter Bright 5 * http://www.digitalmars.com 6 * Distributed under the Boost Software License, Version 1.0. 7 * http://www.boost.org/LICENSE_1_0.txt 8 * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c 9 */ 10 11#include "root/dsystem.h" // strlen() 12#include "root/root.h" 13#include "root/rmem.h" 14#include "root/speller.h" 15 16#include "mars.h" 17#include "init.h" 18#include "identifier.h" 19#include "scope.h" 20#include "attrib.h" 21#include "dsymbol.h" 22#include "declaration.h" 23#include "statement.h" 24#include "aggregate.h" 25#include "module.h" 26#include "id.h" 27#include "template.h" 28 29Scope *Scope::freelist = NULL; 30 31void allocFieldinit(Scope *sc, size_t dim) 32{ 33 sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim); 34 sc->fieldinit_dim = dim; 35} 36 37void freeFieldinit(Scope *sc) 38{ 39 if (sc->fieldinit) 40 mem.xfree(sc->fieldinit); 41 sc->fieldinit = NULL; 42 sc->fieldinit_dim = 0; 43} 44 45Scope *Scope::alloc() 46{ 47 if (freelist) 48 { 49 Scope *s = freelist; 50 freelist = s->enclosing; 51 //printf("freelist %p\n", s); 52 assert(s->flags & SCOPEfree); 53 s->flags &= ~SCOPEfree; 54 return s; 55 } 56 57 return new Scope(); 58} 59 60Scope::Scope() 61{ 62 // Create root scope 63 64 //printf("Scope::Scope() %p\n", this); 65 this->_module = NULL; 66 this->scopesym = NULL; 67 this->sds = NULL; 68 this->enclosing = NULL; 69 this->parent = NULL; 70 this->sw = NULL; 71 this->tf = NULL; 72 this->os = NULL; 73 this->tinst = NULL; 74 this->minst = NULL; 75 this->sbreak = NULL; 76 this->scontinue = NULL; 77 this->fes = NULL; 78 this->callsc = NULL; 79 this->aligndecl = NULL; 80 this->func = NULL; 81 this->slabel = NULL; 82 this->linkage = LINKd; 83 this->cppmangle = CPPMANGLEdefault; 84 this->inlining = PINLINEdefault; 85 this->protection = Prot(PROTpublic); 86 this->explicitProtection = 0; 87 this->stc = 0; 88 this->depdecl = NULL; 89 this->inunion = 0; 90 this->nofree = 0; 91 this->noctor = 0; 92 this->intypeof = 0; 93 this->lastVar = NULL; 94 this->callSuper = 0; 95 this->fieldinit = NULL; 96 this->fieldinit_dim = 0; 97 this->flags = 0; 98 this->lastdc = NULL; 99 this->anchorCounts = NULL; 100 this->prevAnchor = NULL; 101 this->userAttribDecl = NULL; 102} 103 104Scope *Scope::copy() 105{ 106 Scope *sc = Scope::alloc(); 107 *sc = *this; // memcpy 108 109 /* Bugzilla 11777: The copied scope should not inherit fieldinit. 110 */ 111 sc->fieldinit = NULL; 112 113 return sc; 114} 115 116Scope *Scope::createGlobal(Module *_module) 117{ 118 Scope *sc = Scope::alloc(); 119 *sc = Scope(); // memset 120 121 sc->aligndecl = NULL; 122 sc->linkage = LINKd; 123 sc->inlining = PINLINEdefault; 124 sc->protection = Prot(PROTpublic); 125 126 sc->_module = _module; 127 128 sc->tinst = NULL; 129 sc->minst = _module; 130 131 sc->scopesym = new ScopeDsymbol(); 132 sc->scopesym->symtab = new DsymbolTable(); 133 134 // Add top level package as member of this global scope 135 Dsymbol *m = _module; 136 while (m->parent) 137 m = m->parent; 138 m->addMember(NULL, sc->scopesym); 139 m->parent = NULL; // got changed by addMember() 140 141 // Create the module scope underneath the global scope 142 sc = sc->push(_module); 143 sc->parent = _module; 144 return sc; 145} 146 147Scope *Scope::push() 148{ 149 Scope *s = copy(); 150 151 //printf("Scope::push(this = %p) new = %p\n", this, s); 152 assert(!(flags & SCOPEfree)); 153 s->scopesym = NULL; 154 s->sds = NULL; 155 s->enclosing = this; 156 s->slabel = NULL; 157 s->nofree = 0; 158 s->fieldinit = saveFieldInit(); 159 s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint | 160 SCOPEnoaccesscheck | SCOPEignoresymbolvisibility)); 161 s->lastdc = NULL; 162 163 assert(this != s); 164 return s; 165} 166 167Scope *Scope::push(ScopeDsymbol *ss) 168{ 169 //printf("Scope::push(%s)\n", ss->toChars()); 170 Scope *s = push(); 171 s->scopesym = ss; 172 return s; 173} 174 175Scope *Scope::pop() 176{ 177 //printf("Scope::pop() %p nofree = %d\n", this, nofree); 178 Scope *enc = enclosing; 179 180 if (enclosing) 181 { 182 enclosing->callSuper |= callSuper; 183 if (fieldinit) 184 { 185 if (enclosing->fieldinit) 186 { 187 assert(fieldinit != enclosing->fieldinit); 188 size_t dim = fieldinit_dim; 189 for (size_t i = 0; i < dim; i++) 190 enclosing->fieldinit[i] |= fieldinit[i]; 191 } 192 freeFieldinit(this); 193 } 194 } 195 196 if (!nofree) 197 { 198 enclosing = freelist; 199 freelist = this; 200 flags |= SCOPEfree; 201 } 202 203 return enc; 204} 205 206Scope *Scope::startCTFE() 207{ 208 Scope *sc = this->push(); 209 sc->flags = this->flags | SCOPEctfe; 210 return sc; 211} 212 213Scope *Scope::endCTFE() 214{ 215 assert(flags & SCOPEctfe); 216 return pop(); 217} 218 219void Scope::mergeCallSuper(Loc loc, unsigned cs) 220{ 221 // This does a primitive flow analysis to support the restrictions 222 // regarding when and how constructors can appear. 223 // It merges the results of two paths. 224 // The two paths are callSuper and cs; the result is merged into callSuper. 225 226 if (cs != callSuper) 227 { 228 // Have ALL branches called a constructor? 229 int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; 230 int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; 231 232 // Have ANY branches called a constructor? 233 bool aAny = (cs & CSXany_ctor) != 0; 234 bool bAny = (callSuper & CSXany_ctor) != 0; 235 236 // Have any branches returned? 237 bool aRet = (cs & CSXreturn) != 0; 238 bool bRet = (callSuper & CSXreturn) != 0; 239 240 // Have any branches halted? 241 bool aHalt = (cs & CSXhalt) != 0; 242 bool bHalt = (callSuper & CSXhalt) != 0; 243 244 bool ok = true; 245 246 if (aHalt && bHalt) 247 { 248 callSuper = CSXhalt; 249 } 250 else if ((!aHalt && aRet && !aAny && bAny) || 251 (!bHalt && bRet && !bAny && aAny)) 252 { 253 // If one has returned without a constructor call, there must be never 254 // have been ctor calls in the other. 255 ok = false; 256 } 257 else if (aHalt || (aRet && aAll)) 258 { 259 // If one branch has called a ctor and then exited, anything the 260 // other branch has done is OK (except returning without a 261 // ctor call, but we already checked that). 262 callSuper |= cs & (CSXany_ctor | CSXlabel); 263 } 264 else if (bHalt || (bRet && bAll)) 265 { 266 callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); 267 } 268 else 269 { 270 // Both branches must have called ctors, or both not. 271 ok = (aAll == bAll); 272 // If one returned without a ctor, we must remember that 273 // (Don't bother if we've already found an error) 274 if (ok && aRet && !aAny) 275 callSuper |= CSXreturn; 276 callSuper |= cs & (CSXany_ctor | CSXlabel); 277 } 278 if (!ok) 279 error(loc, "one path skips constructor"); 280 } 281} 282 283unsigned *Scope::saveFieldInit() 284{ 285 unsigned *fi = NULL; 286 if (fieldinit) // copy 287 { 288 size_t dim = fieldinit_dim; 289 fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim); 290 for (size_t i = 0; i < dim; i++) 291 fi[i] = fieldinit[i]; 292 } 293 return fi; 294} 295 296static bool mergeFieldInit(unsigned &fieldInit, unsigned fi, bool mustInit) 297{ 298 if (fi != fieldInit) 299 { 300 // Have any branches returned? 301 bool aRet = (fi & CSXreturn) != 0; 302 bool bRet = (fieldInit & CSXreturn) != 0; 303 304 // Have any branches halted? 305 bool aHalt = (fi & CSXhalt) != 0; 306 bool bHalt = (fieldInit & CSXhalt) != 0; 307 308 bool ok; 309 310 if (aHalt && bHalt) 311 { 312 ok = true; 313 fieldInit = CSXhalt; 314 } 315 else if (!aHalt && aRet) 316 { 317 ok = !mustInit || (fi & CSXthis_ctor); 318 fieldInit = fieldInit; 319 } 320 else if (!bHalt && bRet) 321 { 322 ok = !mustInit || (fieldInit & CSXthis_ctor); 323 fieldInit = fi; 324 } 325 else if (aHalt) 326 { 327 ok = !mustInit || (fieldInit & CSXthis_ctor); 328 fieldInit = fieldInit; 329 } 330 else if (bHalt) 331 { 332 ok = !mustInit || (fi & CSXthis_ctor); 333 fieldInit = fi; 334 } 335 else 336 { 337 ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor); 338 fieldInit |= fi; 339 } 340 341 return ok; 342 } 343 return true; 344} 345 346void Scope::mergeFieldInit(Loc loc, unsigned *fies) 347{ 348 if (fieldinit && fies) 349 { 350 FuncDeclaration *f = func; 351 if (fes) f = fes->func; 352 AggregateDeclaration *ad = f->isMember2(); 353 assert(ad); 354 355 for (size_t i = 0; i < ad->fields.dim; i++) 356 { 357 VarDeclaration *v = ad->fields[i]; 358 bool mustInit = (v->storage_class & STCnodefaultctor || 359 v->type->needsNested()); 360 361 if (!::mergeFieldInit(fieldinit[i], fies[i], mustInit)) 362 { 363 ::error(loc, "one path skips field %s", ad->fields[i]->toChars()); 364 } 365 } 366 } 367} 368 369Module *Scope::instantiatingModule() 370{ 371 // TODO: in speculative context, returning 'module' is correct? 372 return minst ? minst : _module; 373} 374 375static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags) 376{ 377 for (Scope *sc = scope; sc; sc = sc->enclosing) 378 { 379 assert(sc != sc->enclosing); 380 if (!sc->scopesym) 381 continue; 382 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags); 383 384 if (sc->scopesym->isModule()) 385 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 386 387 if (Dsymbol *s = sc->scopesym->search(loc, ident, flags)) 388 { 389 if (!(flags & (SearchImportsOnly | IgnoreErrors)) && 390 ident == Id::length && sc->scopesym->isArrayScopeSymbol() && 391 sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags)) 392 { 393 warning(s->loc, "array 'length' hides other 'length' name in outer scope"); 394 } 395 if (pscopesym) 396 *pscopesym = sc->scopesym; 397 return s; 398 } 399 // Stop when we hit a module, but keep going if that is not just under the global scope 400 if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing)) 401 break; 402 } 403 return NULL; 404} 405 406/************************************ 407 * Perform unqualified name lookup by following the chain of scopes up 408 * until found. 409 * 410 * Params: 411 * loc = location to use for error messages 412 * ident = name to look up 413 * pscopesym = if supplied and name is found, set to scope that ident was found in 414 * flags = modify search based on flags 415 * 416 * Returns: 417 * symbol if found, null if not 418 */ 419Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags) 420{ 421 // This function is called only for unqualified lookup 422 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); 423 424 /* If ident is "start at module scope", only look at module scope 425 */ 426 if (ident == Id::empty) 427 { 428 // Look for module scope 429 for (Scope *sc = this; sc; sc = sc->enclosing) 430 { 431 assert(sc != sc->enclosing); 432 if (!sc->scopesym) 433 continue; 434 435 if (Dsymbol *s = sc->scopesym->isModule()) 436 { 437 if (pscopesym) 438 *pscopesym = sc->scopesym; 439 return s; 440 } 441 } 442 return NULL; 443 } 444 445 if (this->flags & SCOPEignoresymbolvisibility) 446 flags |= IgnoreSymbolVisibility; 447 448 Dsymbol *sold = NULL; 449 if (global.params.bug10378 || global.params.check10378) 450 { 451 sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility); 452 if (!global.params.check10378) 453 return sold; 454 455 if (ident == Id::dollar) // Bugzilla 15825 456 return sold; 457 458 // Search both ways 459 } 460 461 // First look in local scopes 462 Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly); 463 if (!s) 464 { 465 // Second look in imported modules 466 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly); 467 /** Still find private symbols, so that symbols that weren't access 468 * checked by the compiler remain usable. Once the deprecation is over, 469 * this should be moved to search_correct instead. 470 */ 471 if (!s && !(flags & IgnoreSymbolVisibility)) 472 { 473 s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility); 474 if (!s) 475 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility); 476 477 if (s && !(flags & IgnoreErrors)) 478 ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars()); 479 } 480 } 481 482 if (global.params.check10378) 483 { 484 Dsymbol *snew = s; 485 if (sold != snew) 486 deprecation10378(loc, sold, snew); 487 if (global.params.bug10378) 488 s = sold; 489 } 490 return s; 491} 492 493Dsymbol *Scope::insert(Dsymbol *s) 494{ 495 if (VarDeclaration *vd = s->isVarDeclaration()) 496 { 497 if (lastVar) 498 vd->lastVar = lastVar; 499 lastVar = vd; 500 } 501 else if (WithScopeSymbol *ss = s->isWithScopeSymbol()) 502 { 503 if (VarDeclaration *vd = ss->withstate->wthis) 504 { 505 if (lastVar) 506 vd->lastVar = lastVar; 507 lastVar = vd; 508 } 509 return NULL; 510 } 511 for (Scope *sc = this; sc; sc = sc->enclosing) 512 { 513 //printf("\tsc = %p\n", sc); 514 if (sc->scopesym) 515 { 516 //printf("\t\tsc->scopesym = %p\n", sc->scopesym); 517 if (!sc->scopesym->symtab) 518 sc->scopesym->symtab = new DsymbolTable(); 519 return sc->scopesym->symtabInsert(s); 520 } 521 } 522 assert(0); 523 return NULL; 524} 525 526/******************************************** 527 * Search enclosing scopes for ClassDeclaration. 528 */ 529 530ClassDeclaration *Scope::getClassScope() 531{ 532 for (Scope *sc = this; sc; sc = sc->enclosing) 533 { 534 if (!sc->scopesym) 535 continue; 536 537 ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); 538 if (cd) 539 return cd; 540 } 541 return NULL; 542} 543 544/******************************************** 545 * Search enclosing scopes for ClassDeclaration. 546 */ 547 548AggregateDeclaration *Scope::getStructClassScope() 549{ 550 for (Scope *sc = this; sc; sc = sc->enclosing) 551 { 552 if (!sc->scopesym) 553 continue; 554 555 AggregateDeclaration *ad = sc->scopesym->isClassDeclaration(); 556 if (ad) 557 return ad; 558 ad = sc->scopesym->isStructDeclaration(); 559 if (ad) 560 return ad; 561 } 562 return NULL; 563} 564 565/******************************************* 566 * For TemplateDeclarations, we need to remember the Scope 567 * where it was declared. So mark the Scope as not 568 * to be free'd. 569 */ 570 571void Scope::setNoFree() 572{ 573 //int i = 0; 574 575 //printf("Scope::setNoFree(this = %p)\n", this); 576 for (Scope *sc = this; sc; sc = sc->enclosing) 577 { 578 //printf("\tsc = %p\n", sc); 579 sc->nofree = 1; 580 581 assert(!(flags & SCOPEfree)); 582 //assert(sc != sc->enclosing); 583 //assert(!sc->enclosing || sc != sc->enclosing->enclosing); 584 //if (++i == 10) 585 //assert(0); 586 } 587} 588 589structalign_t Scope::alignment() 590{ 591 if (aligndecl) 592 return aligndecl->getAlignment(this); 593 else 594 return STRUCTALIGN_DEFAULT; 595} 596 597/************************************************ 598 * Given the failed search attempt, try to find 599 * one with a close spelling. 600 */ 601 602void *scope_search_fp(void *arg, const char *seed, int* cost) 603{ 604 //printf("scope_search_fp('%s')\n", seed); 605 606 /* If not in the lexer's string table, it certainly isn't in the symbol table. 607 * Doing this first is a lot faster. 608 */ 609 size_t len = strlen(seed); 610 if (!len) 611 return NULL; 612 Identifier *id = Identifier::lookup(seed, len); 613 if (!id) 614 return NULL; 615 616 Scope *sc = (Scope *)arg; 617 Module::clearCache(); 618 Dsymbol *scopesym = NULL; 619 Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors); 620 if (s) 621 { 622 for (*cost = 0; sc; sc = sc->enclosing, (*cost)++) 623 if (sc->scopesym == scopesym) 624 break; 625 if (scopesym != s->parent) 626 { 627 (*cost)++; // got to the symbol through an import 628 if (s->prot().kind == PROTprivate) 629 return NULL; 630 } 631 } 632 return (void*)s; 633} 634 635void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew) 636{ 637 // Bugzilla 15857 638 // 639 // The overloadset found via the new lookup rules is either 640 // equal or a subset of the overloadset found via the old 641 // lookup rules, so it suffices to compare the dimension to 642 // check for equality. 643 OverloadSet *osold = NULL; 644 OverloadSet *osnew = NULL; 645 if (sold && (osold = sold->isOverloadSet()) != NULL && 646 snew && (osnew = snew->isOverloadSet()) != NULL && 647 osold->a.dim == osnew->a.dim) 648 return; 649 650 OutBuffer buf; 651 buf.writestring("local import search method found "); 652 if (osold) 653 buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim); 654 else if (sold) 655 buf.printf("%s %s", sold->kind(), sold->toPrettyChars()); 656 else 657 buf.writestring("nothing"); 658 buf.writestring(" instead of "); 659 if (osnew) 660 buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim); 661 else if (snew) 662 buf.printf("%s %s", snew->kind(), snew->toPrettyChars()); 663 else 664 buf.writestring("nothing"); 665 666 deprecation(loc, "%s", buf.peekString()); 667} 668 669Dsymbol *Scope::search_correct(Identifier *ident) 670{ 671 if (global.gag) 672 return NULL; // don't do it for speculative compiles; too time consuming 673 674 return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars); 675} 676 677/************************************ 678 * Maybe `ident` was a C or C++ name. Check for that, 679 * and suggest the D equivalent. 680 * Params: 681 * ident = unknown identifier 682 * Returns: 683 * D identifier string if found, null if not 684 */ 685const char *Scope::search_correct_C(Identifier *ident) 686{ 687 TOK tok; 688 if (ident == Id::C_NULL) 689 tok = TOKnull; 690 else if (ident == Id::C_TRUE) 691 tok = TOKtrue; 692 else if (ident == Id::C_FALSE) 693 tok = TOKfalse; 694 else if (ident == Id::C_unsigned) 695 tok = TOKuns32; 696 else if (ident == Id::C_wchar_t) 697 tok = global.params.isWindows ? TOKwchar : TOKdchar; 698 else 699 return NULL; 700 return Token::toChars(tok); 701} 702