Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1592 lines (1362 sloc) 46.491 kb
// Compiler implementation of the D programming language
// Copyright (c) 1999-2012 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 <stdlib.h>
#include <assert.h>
#include "root.h"
#include "rmem.h"
#include "enum.h"
#include "init.h"
#include "attrib.h"
#include "declaration.h"
#include "aggregate.h"
#include "id.h"
#include "mtype.h"
#include "scope.h"
#include "module.h"
#include "expression.h"
#include "statement.h"
/********************************* ClassDeclaration ****************************/
ClassDeclaration *ClassDeclaration::classinfo;
ClassDeclaration *ClassDeclaration::object;
ClassDeclaration *ClassDeclaration::errorException;
ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
: AggregateDeclaration(loc, id)
{
static char msg[] = "only object.d can define this reserved class name";
if (baseclasses)
// Actually, this is a transfer
this->baseclasses = baseclasses;
else
this->baseclasses = new BaseClasses();
baseClass = NULL;
interfaces_dim = 0;
interfaces = NULL;
vtblInterfaces = NULL;
//printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim);
// For forward references
type = new TypeClass(this);
handle = type;
ctor = NULL;
defaultCtor = NULL;
staticCtor = NULL;
staticDtor = NULL;
#if IN_DMD
vtblsym = NULL;
#endif
vclassinfo = NULL;
if (id)
{ // Look for special class names
if (id == Id::__sizeof || id == Id::__xalignof || id == Id::mangleof)
error("illegal class name");
// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
if (id->toChars()[0] == 'T')
{
if (id == Id::TypeInfo)
{ if (Type::typeinfo)
Type::typeinfo->error("%s", msg);
Type::typeinfo = this;
}
if (id == Id::TypeInfo_Class)
{ if (Type::typeinfoclass)
Type::typeinfoclass->error("%s", msg);
Type::typeinfoclass = this;
}
if (id == Id::TypeInfo_Interface)
{ if (Type::typeinfointerface)
Type::typeinfointerface->error("%s", msg);
Type::typeinfointerface = this;
}
if (id == Id::TypeInfo_Struct)
{ if (Type::typeinfostruct)
Type::typeinfostruct->error("%s", msg);
Type::typeinfostruct = this;
}
if (id == Id::TypeInfo_Typedef)
{ if (Type::typeinfotypedef)
Type::typeinfotypedef->error("%s", msg);
Type::typeinfotypedef = this;
}
if (id == Id::TypeInfo_Pointer)
{ if (Type::typeinfopointer)
Type::typeinfopointer->error("%s", msg);
Type::typeinfopointer = this;
}
if (id == Id::TypeInfo_Array)
{ if (Type::typeinfoarray)
Type::typeinfoarray->error("%s", msg);
Type::typeinfoarray = this;
}
if (id == Id::TypeInfo_StaticArray)
{ //if (Type::typeinfostaticarray)
//Type::typeinfostaticarray->error("%s", msg);
Type::typeinfostaticarray = this;
}
if (id == Id::TypeInfo_AssociativeArray)
{ if (Type::typeinfoassociativearray)
Type::typeinfoassociativearray->error("%s", msg);
Type::typeinfoassociativearray = this;
}
if (id == Id::TypeInfo_Enum)
{ if (Type::typeinfoenum)
Type::typeinfoenum->error("%s", msg);
Type::typeinfoenum = this;
}
if (id == Id::TypeInfo_Function)
{ if (Type::typeinfofunction)
Type::typeinfofunction->error("%s", msg);
Type::typeinfofunction = this;
}
if (id == Id::TypeInfo_Delegate)
{ if (Type::typeinfodelegate)
Type::typeinfodelegate->error("%s", msg);
Type::typeinfodelegate = this;
}
if (id == Id::TypeInfo_Tuple)
{ if (Type::typeinfotypelist)
Type::typeinfotypelist->error("%s", msg);
Type::typeinfotypelist = this;
}
#if DMDV2
if (id == Id::TypeInfo_Const)
{ if (Type::typeinfoconst)
Type::typeinfoconst->error("%s", msg);
Type::typeinfoconst = this;
}
if (id == Id::TypeInfo_Invariant)
{ if (Type::typeinfoinvariant)
Type::typeinfoinvariant->error("%s", msg);
Type::typeinfoinvariant = this;
}
if (id == Id::TypeInfo_Shared)
{ if (Type::typeinfoshared)
Type::typeinfoshared->error("%s", msg);
Type::typeinfoshared = this;
}
if (id == Id::TypeInfo_Wild)
{ if (Type::typeinfowild)
Type::typeinfowild->error("%s", msg);
Type::typeinfowild = this;
}
#endif
}
if (id == Id::Object)
{ if (object)
object->error("%s", msg);
object = this;
}
if (id == Id::Error)
{ if (errorException)
errorException->error("%s", msg);
errorException = this;
}
if (id == Id::ClassInfo)
{ if (classinfo)
classinfo->error("%s", msg);
classinfo = this;
}
if (id == Id::ModuleInfo)
{ if (Module::moduleinfo)
Module::moduleinfo->error("%s", msg);
Module::moduleinfo = this;
}
}
com = 0;
isscope = 0;
isabstract = 0;
isnested = 0;
vthis = NULL;
inuse = 0;
}
Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
{
ClassDeclaration *cd;
//printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
if (s)
cd = (ClassDeclaration *)s;
else
cd = new ClassDeclaration(loc, ident, NULL);
cd->storage_class |= storage_class;
cd->baseclasses->setDim(this->baseclasses->dim);
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
BaseClass *b = this->baseclasses->tdata()[i];
BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
cd->baseclasses->tdata()[i] = b2;
}
ScopeDsymbol::syntaxCopy(cd);
return cd;
}
void ClassDeclaration::semantic(Scope *sc)
{
//printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
//printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
//printf("sc->stc = %x\n", sc->stc);
//{ static int n; if (++n == 20) *(char*)0=0; }
if (!ident) // if anonymous class
{ const char *id = "__anonclass";
ident = Identifier::generateId(id);
}
if (!sc)
sc = scope;
if (!parent && sc->parent && !sc->parent->isModule())
parent = sc->parent;
type = type->semantic(loc, sc);
handle = type;
if (!members) // if forward reference
{ //printf("\tclass '%s' is forward referenced\n", toChars());
return;
}
if (symtab)
{ if (sizeok == SIZEOKdone || !scope)
{ //printf("\tsemantic for '%s' is already completed\n", toChars());
return; // semantic() already completed
}
}
else
symtab = new DsymbolTable();
Scope *scx = NULL;
if (scope)
{ sc = scope;
scx = scope; // save so we don't make redundant copies
scope = NULL;
}
unsigned dprogress_save = Module::dprogress;
#ifdef IN_GCC
methods.setDim(0);
#endif
if (sc->stc & STCdeprecated)
{
isdeprecated = 1;
}
// Expand any tuples in baseclasses[]
for (size_t i = 0; i < baseclasses->dim; )
{ BaseClass *b = baseclasses->tdata()[i];
b->type = b->type->semantic(loc, sc);
Type *tb = b->type->toBasetype();
if (tb->ty == Ttuple)
{ TypeTuple *tup = (TypeTuple *)tb;
enum PROT protection = b->protection;
baseclasses->remove(i);
size_t dim = Parameter::dim(tup->arguments);
for (size_t j = 0; j < dim; j++)
{ Parameter *arg = Parameter::getNth(tup->arguments, j);
b = new BaseClass(arg->type, protection);
baseclasses->insert(i + j, b);
}
}
else
i++;
}
// See if there's a base class as first in baseclasses[]
if (baseclasses->dim)
{ TypeClass *tc;
BaseClass *b;
Type *tb;
b = baseclasses->tdata()[0];
//b->type = b->type->semantic(loc, sc);
tb = b->type->toBasetype();
if (tb->ty != Tclass)
{ if (b->type != Type::terror)
error("base type must be class or interface, not %s", b->type->toChars());
baseclasses->remove(0);
}
else
{
tc = (TypeClass *)(tb);
if (tc->sym->isDeprecated())
{
if (!isDeprecated())
{
// Deriving from deprecated class makes this one deprecated too
isdeprecated = true;
tc->checkDeprecated(loc, sc);
}
}
if (tc->sym->isInterfaceDeclaration())
;
else
{
for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
{
if (cdb == this)
{
error("circular inheritance");
baseclasses->remove(0);
goto L7;
}
}
if (!tc->sym->symtab || tc->sym->sizeok == SIZEOKnone)
{ // Try to resolve forward reference
if (/*sc->mustsemantic &&*/ tc->sym->scope)
tc->sym->semantic(NULL);
}
if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone)
{
//printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars());
//error("forward reference of base class %s", baseClass->toChars());
// Forward reference of base class, try again later
//printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
if (tc->sym->scope)
tc->sym->scope->module->addDeferredSemantic(tc->sym);
scope->module->addDeferredSemantic(this);
return;
}
else
{ baseClass = tc->sym;
b->base = baseClass;
}
L7: ;
}
}
}
// Treat the remaining entries in baseclasses as interfaces
// Check for errors, handle forward references
for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; )
{ TypeClass *tc;
BaseClass *b;
Type *tb;
b = baseclasses->tdata()[i];
b->type = b->type->semantic(loc, sc);
tb = b->type->toBasetype();
if (tb->ty == Tclass)
tc = (TypeClass *)tb;
else
tc = NULL;
if (!tc || !tc->sym->isInterfaceDeclaration())
{ if (b->type != Type::terror)
error("base type must be interface, not %s", b->type->toChars());
baseclasses->remove(i);
continue;
}
else
{
if (tc->sym->isDeprecated())
{
if (!isDeprecated())
{
// Deriving from deprecated class makes this one deprecated too
isdeprecated = true;
tc->checkDeprecated(loc, sc);
}
}
// Check for duplicate interfaces
for (size_t j = (baseClass ? 1 : 0); j < i; j++)
{
BaseClass *b2 = baseclasses->tdata()[j];
if (b2->base == tc->sym)
error("inherits from duplicate interface %s", b2->base->toChars());
}
if (!tc->sym->symtab)
{ // Try to resolve forward reference
if (/*sc->mustsemantic &&*/ tc->sym->scope)
tc->sym->semantic(NULL);
}
b->base = tc->sym;
if (!b->base->symtab || b->base->scope)
{
//error("forward reference of base class %s", baseClass->toChars());
// Forward reference of base, try again later
//printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
if (tc->sym->scope)
tc->sym->scope->module->addDeferredSemantic(tc->sym);
scope->module->addDeferredSemantic(this);
return;
}
}
i++;
}
// If no base class, and this is not an Object, use Object as base class
if (!baseClass && ident != Id::Object)
{
// BUG: what if Object is redefined in an inner scope?
Type *tbase = new TypeIdentifier(0, Id::Object);
BaseClass *b;
TypeClass *tc;
Type *bt;
if (!object)
{
error("missing or corrupt object.d");
fatal();
}
bt = tbase->semantic(loc, sc)->toBasetype();
b = new BaseClass(bt, PROTpublic);
baseclasses->shift(b);
assert(b->type->ty == Tclass);
tc = (TypeClass *)(b->type);
baseClass = tc->sym;
assert(!baseClass->isInterfaceDeclaration());
b->base = baseClass;
}
interfaces_dim = baseclasses->dim;
interfaces = baseclasses->tdata();
if (baseClass)
{
if (baseClass->storage_class & STCfinal)
error("cannot inherit from final class %s", baseClass->toChars());
interfaces_dim--;
interfaces++;
// Copy vtbl[] from base class
vtbl.setDim(baseClass->vtbl.dim);
memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim);
// Inherit properties from base class
com = baseClass->isCOMclass();
isscope = baseClass->isscope;
vthis = baseClass->vthis;
}
else
{
// No base class, so this is the root of the class hierarchy
vtbl.setDim(0);
vtbl.push(this); // leave room for classinfo as first member
}
protection = sc->protection;
storage_class |= sc->stc;
if (sizeok == 0)
{
interfaceSemantic(sc);
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = (*members)[i];
s->addMember(sc, this, 1);
}
/* If this is a nested class, add the hidden 'this'
* member which is a pointer to the enclosing scope.
*/
if (vthis) // if inheriting from nested class
{ // Use the base class's 'this' member
isnested = 1;
if (storage_class & STCstatic)
error("static class cannot inherit from nested class %s", baseClass->toChars());
if (toParent2() != baseClass->toParent2())
{
if (toParent2())
{
error("is nested within %s, but super class %s is nested within %s",
toParent2()->toChars(),
baseClass->toChars(),
baseClass->toParent2()->toChars());
}
else
{
error("is not nested, but super class %s is nested within %s",
baseClass->toChars(),
baseClass->toParent2()->toChars());
}
isnested = 0;
}
}
else if (!(storage_class & STCstatic))
{ Dsymbol *s = toParent2();
if (s)
{
AggregateDeclaration *ad = s->isClassDeclaration();
FuncDeclaration *fd = s->isFuncDeclaration();
if (ad || fd)
{ isnested = 1;
Type *t;
if (ad)
t = ad->handle;
else if (fd)
{ AggregateDeclaration *ad2 = fd->isMember2();
if (ad2)
t = ad2->handle;
else
{
t = new TypePointer(Type::tvoid);
t = t->semantic(0, sc);
}
}
else
assert(0);
assert(!vthis);
vthis = new ThisDeclaration(loc, t);
members->push(vthis);
}
}
}
}
if (storage_class & STCauto)
error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
if (storage_class & STCscope)
isscope = 1;
if (storage_class & STCabstract)
isabstract = 1;
sc = sc->push(this);
sc->stc &= STCsafe | STCtrusted | STCsystem;
sc->parent = this;
sc->inunion = 0;
if (isCOMclass())
{
#if _WIN32
sc->linkage = LINKwindows;
#else
/* This enables us to use COM objects under Linux and
* work with things like XPCOM
*/
sc->linkage = LINKc;
#endif
}
sc->protection = PROTpublic;
sc->explicitProtection = 0;
sc->structalign = 8;
structalign = sc->structalign;
if (baseClass)
{ sc->offset = baseClass->structsize;
alignsize = baseClass->alignsize;
// if (isnested)
// sc->offset += PTRSIZE; // room for uplevel context pointer
}
else
{ sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor
alignsize = PTRSIZE;
}
structsize = sc->offset;
Scope scsave = *sc;
size_t members_dim = members->dim;
sizeok = SIZEOKnone;
/* Set scope so if there are forward references, we still might be able to
* resolve individual members like enums.
*/
for (size_t i = 0; i < members_dim; i++)
{ Dsymbol *s = (*members)[i];
/* There are problems doing this in the general case because
* Scope keeps track of things like 'offset'
*/
if (s->isEnumDeclaration() ||
(s->isAggregateDeclaration() && s->ident) ||
s->isTemplateMixin() ||
s->isAliasDeclaration())
{
//printf("setScope %s %s\n", s->kind(), s->toChars());
s->setScope(sc);
}
}
for (size_t i = 0; i < members_dim; i++)
{ Dsymbol *s = (*members)[i];
s->semantic(sc);
}
// Set the offsets of the fields and determine the size of the class
unsigned offset = structsize;
bool isunion = isUnionDeclaration() != NULL;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->setFieldOffset(this, &offset, false);
}
sc->offset = structsize;
if (global.gag && global.gaggedErrors != errors)
{ // The type is no good, yet the error messages were gagged.
type = Type::terror;
}
if (sizeok == 2) // failed due to forward references
{ // semantic() failed due to forward references
// Unwind what we did, and defer it for later
for (size_t i = 0; i < fields.dim; i++)
{ Dsymbol *s = fields[i];
VarDeclaration *vd = s->isVarDeclaration();
if (vd)
vd->offset = 0;
}
fields.setDim(0);
structsize = 0;
alignsize = 0;
structalign = 0;
sc = sc->pop();
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
scope->module->addDeferredSemantic(this);
Module::dprogress = dprogress_save;
//printf("\tsemantic('%s') failed due to forward references\n", toChars());
return;
}
//printf("\tsemantic('%s') successful\n", toChars());
//members->print();
/* Look for special member functions.
* They must be in this class, not in a base class.
*/
ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration()))
ctor = NULL;
// dtor = (DtorDeclaration *)search(Id::dtor, 0);
// if (dtor && dtor->toParent() != this)
// dtor = NULL;
// inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
// if (inv && inv->toParent() != this)
// inv = NULL;
// Can be in base class
aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
// If this class has no constructor, but base class does, create
// a constructor:
// this() { }
if (!ctor && baseClass && baseClass->ctor)
{
//printf("Creating default this(){} for class %s\n", toChars());
CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0);
ctor->fbody = new CompoundStatement(0, new Statements());
members->push(ctor);
ctor->addMember(sc, this, 1);
*sc = scsave; // why? What about sc->nofree?
ctor->semantic(sc);
this->ctor = ctor;
defaultCtor = ctor;
}
#if 0
if (baseClass)
{ if (!aggDelete)
aggDelete = baseClass->aggDelete;
if (!aggNew)
aggNew = baseClass->aggNew;
}
#endif
// Allocate instance of each new interface
sc->offset = structsize;
for (size_t i = 0; i < vtblInterfaces->dim; i++)
{
BaseClass *b = (*vtblInterfaces)[i];
unsigned thissize = PTRSIZE;
alignmember(structalign, thissize, &sc->offset);
assert(b->offset == 0);
b->offset = sc->offset;
// Take care of single inheritance offsets
while (b->baseInterfaces_dim)
{
b = &b->baseInterfaces[0];
b->offset = sc->offset;
}
sc->offset += thissize;
if (alignsize < thissize)
alignsize = thissize;
}
structsize = sc->offset;
sizeok = SIZEOKdone;
Module::dprogress++;
dtor = buildDtor(sc);
sc->pop();
#if 0 // Do not call until toObjfile() because of forward references
// Fill in base class vtbl[]s
for (i = 0; i < vtblInterfaces->dim; i++)
{
BaseClass *b = vtblInterfaces->tdata()[i];
//b->fillVtbl(this, &b->vtbl, 1);
}
#endif
//printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
}
void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (!isAnonymous())
{
buf->printf("%s ", kind());
buf->writestring(toChars());
if (baseclasses->dim)
buf->writestring(" : ");
}
for (size_t i = 0; i < baseclasses->dim; i++)
{
BaseClass *b = baseclasses->tdata()[i];
if (i)
buf->writeByte(',');
//buf->writestring(b->base->ident->toChars());
b->type->toCBuffer(buf, NULL, hgs);
}
if (members)
{
buf->writenl();
buf->writeByte('{');
buf->writenl();
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
buf->writestring(" ");
s->toCBuffer(buf, hgs);
}
buf->writestring("}");
}
else
buf->writeByte(';');
buf->writenl();
}
#if 0
void ClassDeclaration::defineRef(Dsymbol *s)
{
ClassDeclaration *cd;
AggregateDeclaration::defineRef(s);
cd = s->isClassDeclaration();
baseType = cd->baseType;
cd->baseType = NULL;
}
#endif
/*********************************************
* Determine if 'this' is a base class of cd.
* This is used to detect circular inheritance only.
*/
int ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
{
if (!cd)
return 0;
//printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{ BaseClass *b = cd->baseclasses->tdata()[i];
if (b->base == this || isBaseOf2(b->base))
return 1;
}
return 0;
}
/*******************************************
* Determine if 'this' is a base class of cd.
*/
int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
{
//printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
if (poffset)
*poffset = 0;
while (cd)
{
/* cd->baseClass might not be set if cd is forward referenced.
*/
if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration())
{
cd->semantic(NULL);
if (!cd->baseClass)
cd->error("base class is forward referenced by %s", toChars());
}
if (this == cd->baseClass)
return 1;
cd = cd->baseClass;
}
return 0;
}
/*********************************************
* Determine if 'this' has complete base class information.
* This is used to detect forward references in covariant overloads.
*/
int ClassDeclaration::isBaseInfoComplete()
{
if (!baseClass)
return ident == Id::Object;
for (size_t i = 0; i < baseclasses->dim; i++)
{ BaseClass *b = baseclasses->tdata()[i];
if (!b->base || !b->base->isBaseInfoComplete())
return 0;
}
return 1;
}
Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
{
Dsymbol *s;
//printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
if (scope && !symtab)
{ Scope *sc = scope;
sc->mustsemantic++;
// If speculatively gagged, ungag now.
unsigned oldgag = global.gag;
if (global.isSpeculativeGagging())
global.gag = 0;
semantic(sc);
global.gag = oldgag;
sc->mustsemantic--;
}
if (!members || !symtab)
{
error("is forward referenced when looking for '%s'", ident->toChars());
//*(char*)0=0;
return NULL;
}
s = ScopeDsymbol::search(loc, ident, flags);
if (!s)
{
// Search bases classes in depth-first, left to right order
for (size_t i = 0; i < baseclasses->dim; i++)
{
BaseClass *b = baseclasses->tdata()[i];
if (b->base)
{
if (!b->base->symtab)
error("base %s is forward referenced", b->base->ident->toChars());
else
{
s = b->base->search(loc, ident, flags);
if (s == this) // happens if s is nested in this and derives from this
s = NULL;
else if (s)
break;
}
}
}
}
return s;
}
Dsymbol *ClassDeclaration::searchBase(Loc loc, Identifier *ident)
{
// Search bases classes in depth-first, left to right order
for (size_t i = 0; i < baseclasses->dim; i++)
{
BaseClass *b = (*baseclasses)[i];
Dsymbol *cdb = b->type->isClassHandle();
if (cdb->ident->equals(ident))
return cdb;
cdb = ((ClassDeclaration *)cdb)->searchBase(loc, ident);
if (cdb)
return cdb;
}
return NULL;
}
/**********************************************************
* fd is in the vtbl[] for this class.
* Return 1 if function is hidden (not findable through search).
*/
#if DMDV2
int isf(void *param, FuncDeclaration *fd)
{
//printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
return param == fd;
}
int ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
{
//printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars());
Dsymbol *s = search(0, fd->ident, 4|2);
if (!s)
{ //printf("not found\n");
/* Because, due to a hack, if there are multiple definitions
* of fd->ident, NULL is returned.
*/
return 0;
}
FuncDeclaration *fdstart = s->toAlias()->isFuncDeclaration();
//printf("%s fdstart = %p\n", s->kind(), fdstart);
if (overloadApply(fdstart, &isf, fd))
return 0;
return !fd->parent->isTemplateMixin();
}
#endif
/****************
* Find virtual function matching identifier and type.
* Used to build virtual function tables for interface implementations.
*/
FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
{
//printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
FuncDeclaration *fdmatch = NULL;
FuncDeclaration *fdambig = NULL;
ClassDeclaration *cd = this;
Dsymbols *vtbl = &cd->vtbl;
while (1)
{
for (size_t i = 0; i < vtbl->dim; i++)
{
FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration();
if (!fd)
continue; // the first entry might be a ClassInfo
//printf("\t[%d] = %s\n", i, fd->toChars());
if (ident == fd->ident &&
fd->type->covariant(tf) == 1)
{ //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration());
if (!fdmatch)
goto Lfd;
{
// Function type matcing: exact > covariant
int m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch;
int m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
}
{
// The way of definition: non-mixin > mixin
int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
int m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
}
Lambig:
fdambig = fd;
//printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
continue;
Lfd:
fdmatch = fd, fdambig = NULL;
//printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
continue;
Lfdmatch:
continue;
}
//else printf("\t\t%d\n", fd->type->covariant(tf));
}
if (!cd)
break;
vtbl = &cd->vtblFinal;
cd = cd->baseClass;
}
if (fdambig)
error("ambiguous virtual function %s", fdambig->toChars());
return fdmatch;
}
void ClassDeclaration::interfaceSemantic(Scope *sc)
{
vtblInterfaces = new BaseClasses();
vtblInterfaces->reserve(interfaces_dim);
for (size_t i = 0; i < interfaces_dim; i++)
{
BaseClass *b = interfaces[i];
// If this is an interface, and it derives from a COM interface,
// then this is a COM interface too.
if (b->base->isCOMinterface())
com = 1;
vtblInterfaces->push(b);
b->copyBaseInterfaces(vtblInterfaces);
}
}
/****************************************
*/
int ClassDeclaration::isCOMclass()
{
return com;
}
int ClassDeclaration::isCOMinterface()
{
return 0;
}
#if DMDV2
int ClassDeclaration::isCPPinterface()
{
return 0;
}
#endif
/****************************************
*/
int ClassDeclaration::isAbstract()
{
if (isabstract)
return TRUE;
for (size_t i = 1; i < vtbl.dim; i++)
{
FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration();
//printf("\tvtbl[%d] = %p\n", i, fd);
if (!fd || fd->isAbstract())
{
isabstract |= 1;
return TRUE;
}
}
return FALSE;
}
/****************************************
* Returns !=0 if there's an extra member which is the 'this'
* pointer to the enclosing context (enclosing class or function)
*/
int ClassDeclaration::isNested()
{
return isnested;
}
/****************************************
* Determine if slot 0 of the vtbl[] is reserved for something else.
* For class objects, yes, this is where the classinfo ptr goes.
* For COM interfaces, no.
* For non-COM interfaces, yes, this is where the Interface ptr goes.
*/
int ClassDeclaration::vtblOffset()
{
return 1;
}
/****************************************
*/
const char *ClassDeclaration::kind()
{
return "class";
}
/****************************************
*/
void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
{
aclasses->push(this);
}
/********************************* InterfaceDeclaration ****************************/
InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
: ClassDeclaration(loc, id, baseclasses)
{
com = 0;
if (id == Id::IUnknown) // IUnknown is the root of all COM objects
com = 1;
}
Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
{
InterfaceDeclaration *id;
if (s)
id = (InterfaceDeclaration *)s;
else
id = new InterfaceDeclaration(loc, ident, NULL);
ClassDeclaration::syntaxCopy(id);
return id;
}
void InterfaceDeclaration::semantic(Scope *sc)
{
//printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
if (inuse)
return;
if (!sc)
sc = scope;
if (!parent && sc->parent && !sc->parent->isModule())
parent = sc->parent;
type = type->semantic(loc, sc);
handle = type;
if (!members) // if forward reference
{ //printf("\tinterface '%s' is forward referenced\n", toChars());
return;
}
if (symtab) // if already done
{ if (!scope)
return;
}
else
symtab = new DsymbolTable();
Scope *scx = NULL;
if (scope)
{ sc = scope;
scx = scope; // save so we don't make redundant copies
scope = NULL;
}
if (sc->stc & STCdeprecated)
{
isdeprecated = true;
}
// Expand any tuples in baseclasses[]
for (size_t i = 0; i < baseclasses->dim; )
{ BaseClass *b = (*baseclasses)[0];
b->type = b->type->semantic(loc, sc);
Type *tb = b->type->toBasetype();
if (tb->ty == Ttuple)
{ TypeTuple *tup = (TypeTuple *)tb;
enum PROT protection = b->protection;
baseclasses->remove(i);
size_t dim = Parameter::dim(tup->arguments);
for (size_t j = 0; j < dim; j++)
{ Parameter *arg = Parameter::getNth(tup->arguments, j);
b = new BaseClass(arg->type, protection);
baseclasses->insert(i + j, b);
}
}
else
i++;
}
// Check for errors, handle forward references
for (size_t i = 0; i < baseclasses->dim; )
{ TypeClass *tc;
BaseClass *b;
Type *tb;
b = baseclasses->tdata()[i];
b->type = b->type->semantic(loc, sc);
tb = b->type->toBasetype();
if (tb->ty == Tclass)
tc = (TypeClass *)tb;
else
tc = NULL;
if (!tc || !tc->sym->isInterfaceDeclaration())
{ if (b->type != Type::terror)
error("base type must be interface, not %s", b->type->toChars());
baseclasses->remove(i);
continue;
}
else
{
// Check for duplicate interfaces
for (size_t j = 0; j < i; j++)
{
BaseClass *b2 = baseclasses->tdata()[j];
if (b2->base == tc->sym)
error("inherits from duplicate interface %s", b2->base->toChars());
}
b->base = tc->sym;
if (b->base == this || isBaseOf2(b->base))
{
error("circular inheritance of interface");
baseclasses->remove(i);
continue;
}
if (!b->base->symtab)
{ // Try to resolve forward reference
if (sc->mustsemantic && b->base->scope)
b->base->semantic(NULL);
}
if (!b->base->symtab || b->base->scope || b->base->inuse)
{
//error("forward reference of base class %s", baseClass->toChars());
// Forward reference of base, try again later
//printf("\ttry later, forward reference of base %s\n", b->base->toChars());
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
scope->module->addDeferredSemantic(this);
return;
}
}
i++;
}
interfaces_dim = baseclasses->dim;
interfaces = (BaseClass **)baseclasses->data;
interfaceSemantic(sc);
if (vtblOffset())
vtbl.push(this); // leave room at vtbl[0] for classinfo
// Cat together the vtbl[]'s from base interfaces
for (size_t i = 0; i < interfaces_dim; i++)
{ BaseClass *b = interfaces[i];
// Skip if b has already appeared
for (size_t k = 0; k < i; k++)
{
if (b == interfaces[k])
goto Lcontinue;
}
// Copy vtbl[] from base class
if (b->base->vtblOffset())
{ size_t d = b->base->vtbl.dim;
if (d > 1)
{
vtbl.reserve(d - 1);
for (size_t j = 1; j < d; j++)
vtbl.push((Dsymbol *)b->base->vtbl.data[j]);
}
}
else
{
vtbl.append(&b->base->vtbl);
}
Lcontinue:
;
}
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = (*members)[i];
s->addMember(sc, this, 1);
}
sc = sc->push(this);
sc->stc &= STCsafe | STCtrusted | STCsystem;
sc->parent = this;
if (isCOMinterface())
sc->linkage = LINKwindows;
sc->structalign = 8;
sc->protection = PROTpublic;
sc->explicitProtection = 0;
structalign = sc->structalign;
sc->offset = PTRSIZE * 2;
structsize = sc->offset;
inuse++;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->semantic(sc);
}
inuse--;
//members->print();
sc->pop();
//printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
}
/*******************************************
* Determine if 'this' is a base class of cd.
* (Actually, if it is an interface supported by cd)
* Output:
* *poffset offset to start of class
* OFFSET_RUNTIME must determine offset at runtime
* Returns:
* 0 not a base
* 1 is a base
*/
int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
{
unsigned j;
//printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
assert(!baseClass);
for (j = 0; j < cd->interfaces_dim; j++)
{
BaseClass *b = cd->interfaces[j];
//printf("\tbase %s\n", b->base->toChars());
if (this == b->base)
{
//printf("\tfound at offset %d\n", b->offset);
if (poffset)
{ *poffset = b->offset;
if (j && cd->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
}
return 1;
}
if (isBaseOf(b, poffset))
{ if (j && poffset && cd->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
return 1;
}
}
if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
return 1;
if (poffset)
*poffset = 0;
return 0;
}
int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
{
//printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
for (unsigned j = 0; j < bc->baseInterfaces_dim; j++)
{
BaseClass *b = &bc->baseInterfaces[j];
if (this == b->base)
{
if (poffset)
{ *poffset = b->offset;
if (j && bc->base->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
}
return 1;
}
if (isBaseOf(b, poffset))
{ if (j && poffset && bc->base->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
return 1;
}
}
if (poffset)
*poffset = 0;
return 0;
}
/*********************************************
* Determine if 'this' has clomplete base class information.
* This is used to detect forward references in covariant overloads.
*/
int InterfaceDeclaration::isBaseInfoComplete()
{
assert(!baseClass);
for (size_t i = 0; i < baseclasses->dim; i++)
{ BaseClass *b = baseclasses->tdata()[i];
if (!b->base || !b->base->isBaseInfoComplete ())
return 0;
}
return 1;
}
/****************************************
* Determine if slot 0 of the vtbl[] is reserved for something else.
* For class objects, yes, this is where the ClassInfo ptr goes.
* For COM interfaces, no.
* For non-COM interfaces, yes, this is where the Interface ptr goes.
*/
int InterfaceDeclaration::vtblOffset()
{
if (isCOMinterface())
return 0;
return 1;
}
int InterfaceDeclaration::isCOMinterface()
{
return com;
}
#if DMDV2
int InterfaceDeclaration::isCPPinterface()
{
return cpp;
}
#endif
/*******************************************
*/
const char *InterfaceDeclaration::kind()
{
return "interface";
}
/******************************** BaseClass *****************************/
BaseClass::BaseClass()
{
memset(this, 0, sizeof(BaseClass));
}
BaseClass::BaseClass(Type *type, enum PROT protection)
{
//printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
this->type = type;
this->protection = protection;
base = NULL;
offset = 0;
baseInterfaces_dim = 0;
baseInterfaces = NULL;
}
/****************************************
* Fill in vtbl[] for base class based on member functions of class cd.
* Input:
* vtbl if !=NULL, fill it in
* newinstance !=0 means all entries must be filled in by members
* of cd, not members of any base classes of cd.
* Returns:
* !=0 if any entries were filled in by members of cd (not exclusively
* by base classes)
*/
int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance)
{
ClassDeclaration *id = base;
int result = 0;
//printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
if (vtbl)
vtbl->setDim(base->vtbl.dim);
// first entry is ClassInfo reference
for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++)
{
FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration();
FuncDeclaration *fd;
TypeFunction *tf;
//printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
assert(ifd);
// Find corresponding function in this class
tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
fd = cd->findFunc(ifd->ident, tf);
if (fd && !fd->isAbstract())
{
//printf(" found\n");
// Check that calling conventions match
if (fd->linkage != ifd->linkage)
fd->error("linkage doesn't match interface function");
// Check that it is current
if (newinstance &&
fd->toParent() != cd &&
ifd->toParent() == base)
cd->error("interface function %s.%s is not implemented",
id->toChars(), ifd->ident->toChars());
if (fd->toParent() == cd)
result = 1;
}
else
{
//printf(" not found\n");
// BUG: should mark this class as abstract?
if (!cd->isAbstract())
cd->error("interface function %s.%s isn't implemented",
id->toChars(), ifd->ident->toChars());
fd = NULL;
}
if (vtbl)
vtbl->data[j] = fd;
}
return result;
}
void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
{
//printf("+copyBaseInterfaces(), %s\n", base->toChars());
// if (baseInterfaces_dim)
// return;
baseInterfaces_dim = base->interfaces_dim;
baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass));
//printf("%s.copyBaseInterfaces()\n", base->toChars());
for (int i = 0; i < baseInterfaces_dim; i++)
{
BaseClass *b = &baseInterfaces[i];
BaseClass *b2 = base->interfaces[i];
assert(b2->vtbl.dim == 0); // should not be filled yet
memcpy(b, b2, sizeof(BaseClass));
if (i) // single inheritance is i==0
vtblInterfaces->push(b); // only need for M.I.
b->copyBaseInterfaces(vtblInterfaces);
}
//printf("-copyBaseInterfaces\n");
}
Jump to Line
Something went wrong with that request. Please try again.