ldc/dmd2/scope.c

364 lines
8.4 KiB
C

// 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 <stdio.h>
#include <assert.h>
#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);
}
}