mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-08 03:46:02 +03:00
364 lines
8.4 KiB
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);
|
|
}
|
|
}
|