// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include #include #include "root.h" #include "mars.h" #include "init.h" #include "identifier.h" #include "attrib.h" #include "dsymbol.h" #include "scope.h" #include "declaration.h" #include "aggregate.h" #include "module.h" #include "id.h" Scope *Scope::freelist = NULL; void *Scope::operator new(size_t size) { if (freelist) { Scope *s = freelist; freelist = s->enclosing; //printf("freelist %p\n", s); assert(s->flags & SCOPEfree); s->flags &= ~SCOPEfree; return s; } void *p = ::operator new(size); //printf("new %p\n", p); return p; } Scope::Scope() { // Create root scope //printf("Scope::Scope() %p\n", this); this->module = NULL; this->scopesym = NULL; this->sd = NULL; this->enclosing = NULL; this->parent = NULL; this->sw = NULL; this->tf = NULL; this->tfOfTry = NULL; this->tinst = NULL; this->sbreak = NULL; this->scontinue = NULL; this->fes = NULL; this->structalign = global.structalign; this->func = NULL; this->slabel = NULL; this->linkage = LINKd; this->protection = PROTpublic; this->explicitProtection = 0; this->stc = 0; this->offset = 0; this->inunion = 0; this->incontract = 0; this->nofree = 0; this->noctor = 0; this->noaccesscheck = 0; this->intypeof = 0; this->parameterSpecialization = 0; this->callSuper = 0; this->flags = 0; this->anonAgg = NULL; this->lastdc = NULL; this->lastoffset = 0; this->docbuf = NULL; } Scope::Scope(Scope *enclosing) { //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); assert(!(enclosing->flags & SCOPEfree)); this->module = enclosing->module; this->func = enclosing->func; this->parent = enclosing->parent; this->scopesym = NULL; this->sd = NULL; this->sw = enclosing->sw; this->tf = enclosing->tf; this->tfOfTry = enclosing->tfOfTry; this->tinst = enclosing->tinst; this->sbreak = enclosing->sbreak; this->scontinue = enclosing->scontinue; this->fes = enclosing->fes; this->structalign = enclosing->structalign; this->enclosing = enclosing; #ifdef DEBUG if (enclosing->enclosing) assert(!(enclosing->enclosing->flags & SCOPEfree)); if (this == enclosing->enclosing) { printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); } assert(this != enclosing->enclosing); #endif this->slabel = NULL; this->linkage = enclosing->linkage; this->protection = enclosing->protection; this->explicitProtection = enclosing->explicitProtection; this->stc = enclosing->stc; this->offset = 0; this->inunion = enclosing->inunion; this->incontract = enclosing->incontract; this->nofree = 0; this->noctor = enclosing->noctor; this->noaccesscheck = enclosing->noaccesscheck; this->intypeof = enclosing->intypeof; this->parameterSpecialization = enclosing->parameterSpecialization; this->callSuper = enclosing->callSuper; this->flags = 0; this->anonAgg = NULL; this->lastdc = NULL; this->lastoffset = 0; this->docbuf = enclosing->docbuf; assert(this != enclosing); } Scope *Scope::createGlobal(Module *module) { Scope *sc; sc = new Scope(); sc->module = module; sc->scopesym = new ScopeDsymbol(); sc->scopesym->symtab = new DsymbolTable(); // Add top level package as member of this global scope Dsymbol *m = module; while (m->parent) m = m->parent; m->addMember(NULL, sc->scopesym, 1); m->parent = NULL; // got changed by addMember() // Create the module scope underneath the global scope sc = sc->push(module); sc->parent = module; return sc; } Scope *Scope::push() { //printf("Scope::push()\n"); Scope *s = new Scope(this); assert(this != s); return s; } Scope *Scope::push(ScopeDsymbol *ss) { //printf("Scope::push(%s)\n", ss->toChars()); Scope *s = push(); s->scopesym = ss; return s; } Scope *Scope::pop() { //printf("Scope::pop() %p nofree = %d\n", this, nofree); Scope *enc = enclosing; if (enclosing) enclosing->callSuper |= callSuper; if (!nofree) { enclosing = freelist; freelist = this; flags |= SCOPEfree; } return enc; } void Scope::mergeCallSuper(Loc loc, unsigned cs) { // This does a primitive flow analysis to support the restrictions // regarding when and how constructors can appear. // It merges the results of two paths. // The two paths are callSuper and cs; the result is merged into callSuper. if (cs != callSuper) { int a; int b; callSuper |= cs & (CSXany_ctor | CSXlabel); if (cs & CSXreturn) { } else if (callSuper & CSXreturn) { callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); } else { a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; if (a != b) error(loc, "one path skips constructor"); callSuper |= cs; } } } Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) { Dsymbol *s; Scope *sc; //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); if (ident == Id::empty) { // Look for module scope for (sc = this; sc; sc = sc->enclosing) { assert(sc != sc->enclosing); if (sc->scopesym) { s = sc->scopesym->isModule(); if (s) { //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); if (pscopesym) *pscopesym = sc->scopesym; return s; } } } return NULL; } for (sc = this; sc; sc = sc->enclosing) { assert(sc != sc->enclosing); if (sc->scopesym) { //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); s = sc->scopesym->search(loc, ident, 0); if (s) { if ((global.params.warnings || global.params.Dversion > 1) && ident == Id::length && sc->scopesym->isArrayScopeSymbol() && sc->enclosing && sc->enclosing->search(loc, ident, NULL)) { // WTF ? if (global.params.warnings) fprintf(stdmsg, "warning - "); error(s->loc, "array 'length' hides other 'length' name in outer scope"); } //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); if (pscopesym) *pscopesym = sc->scopesym; return s; } } } return NULL; } Dsymbol *Scope::insert(Dsymbol *s) { Scope *sc; for (sc = this; sc; sc = sc->enclosing) { //printf("\tsc = %p\n", sc); if (sc->scopesym) { //printf("\t\tsc->scopesym = %p\n", sc->scopesym); if (!sc->scopesym->symtab) sc->scopesym->symtab = new DsymbolTable(); return sc->scopesym->symtab->insert(s); } } assert(0); return NULL; } /******************************************** * Search enclosing scopes for ClassDeclaration. */ ClassDeclaration *Scope::getClassScope() { Scope *sc; for (sc = this; sc; sc = sc->enclosing) { ClassDeclaration *cd; if (sc->scopesym) { cd = sc->scopesym->isClassDeclaration(); if (cd) return cd; } } return NULL; } /******************************************** * Search enclosing scopes for ClassDeclaration. */ AggregateDeclaration *Scope::getStructClassScope() { Scope *sc; for (sc = this; sc; sc = sc->enclosing) { AggregateDeclaration *ad; if (sc->scopesym) { ad = sc->scopesym->isClassDeclaration(); if (ad) return ad; else { ad = sc->scopesym->isStructDeclaration(); if (ad) return ad; } } } return NULL; } /******************************************* * For TemplateDeclarations, we need to remember the Scope * where it was declared. So mark the Scope as not * to be free'd. */ void Scope::setNoFree() { Scope *sc; //int i = 0; //printf("Scope::setNoFree(this = %p)\n", this); for (sc = this; sc; sc = sc->enclosing) { //printf("\tsc = %p\n", sc); sc->nofree = 1; assert(!(flags & SCOPEfree)); //assert(sc != sc->enclosing); //assert(!sc->enclosing || sc != sc->enclosing->enclosing); //if (++i == 10) //assert(0); } }