mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-08 03:46:02 +03:00

Changed ClassInfo generation to no longer access the default initializer of ClassInfo, fixes problems with index mismatch.
1420 lines
34 KiB
C
1420 lines
34 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2008 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 "mem.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(Loc loc, Identifier *id, BaseClasses *baseclasses)
|
|
: AggregateDeclaration(loc, id)
|
|
{
|
|
static char msg[] = "only object.d can define this reserved class name";
|
|
|
|
if (baseclasses)
|
|
this->baseclasses = *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;
|
|
|
|
staticCtor = NULL;
|
|
staticDtor = NULL;
|
|
|
|
vtblsym = NULL;
|
|
vclassinfo = NULL;
|
|
|
|
if (id)
|
|
{ // Look for special class names
|
|
|
|
if (id == Id::__sizeof || id == Id::alignof || 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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (id == Id::Object)
|
|
{ if (object)
|
|
object->error("%s", msg);
|
|
object = 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;
|
|
isauto = 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 (int i = 0; i < cd->baseclasses.dim; i++)
|
|
{
|
|
BaseClass *b = (BaseClass *)this->baseclasses.data[i];
|
|
BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
|
|
cd->baseclasses.data[i] = b2;
|
|
}
|
|
|
|
ScopeDsymbol::syntaxCopy(cd);
|
|
return cd;
|
|
}
|
|
|
|
void ClassDeclaration::semantic(Scope *sc)
|
|
{ int i;
|
|
unsigned offset;
|
|
|
|
//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 (!scope)
|
|
{
|
|
if (!parent && sc->parent && !sc->parent->isModule())
|
|
parent = sc->parent;
|
|
|
|
type = type->semantic(loc, sc);
|
|
handle = handle->semantic(loc, sc);
|
|
}
|
|
if (!members) // if forward reference
|
|
{ //printf("\tclass '%s' is forward referenced\n", toChars());
|
|
return;
|
|
}
|
|
if (symtab)
|
|
{ if (!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;
|
|
}
|
|
#ifdef IN_GCC
|
|
methods.setDim(0);
|
|
#endif
|
|
|
|
if (sc->stc & STCdeprecated)
|
|
{
|
|
isdeprecated = 1;
|
|
}
|
|
|
|
if (sc->linkage == LINKcpp)
|
|
error("cannot create C++ classes");
|
|
|
|
// Expand any tuples in baseclasses[]
|
|
for (i = 0; i < baseclasses.dim; )
|
|
{ BaseClass *b = (BaseClass *)baseclasses.data[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 = Argument::dim(tup->arguments);
|
|
for (size_t j = 0; j < dim; j++)
|
|
{ Argument *arg = Argument::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 = (BaseClass *)baseclasses.data[0];
|
|
//b->type = b->type->semantic(loc, sc);
|
|
tb = b->type->toBasetype();
|
|
if (tb->ty != Tclass)
|
|
{ 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 = 1;
|
|
|
|
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->scope || tc->sym->sizeok == 0)
|
|
{
|
|
//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();
|
|
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 (i = (baseClass ? 1 : 0); i < baseclasses.dim; )
|
|
{ TypeClass *tc;
|
|
BaseClass *b;
|
|
Type *tb;
|
|
|
|
b = (BaseClass *)baseclasses.data[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())
|
|
{
|
|
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 = 1;
|
|
|
|
tc->checkDeprecated(loc, sc);
|
|
}
|
|
}
|
|
|
|
// Check for duplicate interfaces
|
|
for (size_t j = (baseClass ? 1 : 0); j < i; j++)
|
|
{
|
|
BaseClass *b2 = (BaseClass *)baseclasses.data[j];
|
|
if (b2->base == tc->sym)
|
|
error("inherits from duplicate interface %s", b2->base->toChars());
|
|
}
|
|
|
|
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();
|
|
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 = (BaseClass **)baseclasses.data;
|
|
|
|
|
|
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.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim);
|
|
|
|
// Inherit properties from base class
|
|
com = baseClass->isCOMclass();
|
|
isauto = baseClass->isauto;
|
|
vthis = baseClass->vthis;
|
|
storage_class |= baseClass->storage_class & (STCconst | STCinvariant);
|
|
}
|
|
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 (i = 0; i < members->dim; i++)
|
|
{
|
|
Dsymbol *s = (Dsymbol *)members->data[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)
|
|
{
|
|
ClassDeclaration *cd = s->isClassDeclaration();
|
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
|
|
|
|
|
if (cd || fd)
|
|
{ isnested = 1;
|
|
Type *t;
|
|
if (cd)
|
|
t = cd->type;
|
|
else if (fd)
|
|
{ AggregateDeclaration *ad = fd->isMember2();
|
|
if (ad)
|
|
t = ad->handle;
|
|
else
|
|
{
|
|
t = new TypePointer(Type::tvoid);
|
|
t = t->semantic(0, sc);
|
|
}
|
|
}
|
|
else
|
|
assert(0);
|
|
assert(!vthis);
|
|
vthis = new ThisDeclaration(t);
|
|
members->push(vthis);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (storage_class & (STCauto | STCscope))
|
|
isauto = 1;
|
|
if (storage_class & STCabstract)
|
|
isabstract = 1;
|
|
if (storage_class & STCinvariant)
|
|
type = type->invariantOf();
|
|
else if (storage_class & STCconst)
|
|
type = type->constOf();
|
|
|
|
sc = sc->push(this);
|
|
sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
|
|
STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
|
|
sc->stc |= storage_class & (STCconst | STCinvariant);
|
|
sc->parent = this;
|
|
sc->inunion = 0;
|
|
|
|
if (isCOMclass())
|
|
sc->linkage = LINKwindows;
|
|
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;
|
|
int members_dim = members->dim;
|
|
sizeok = 0;
|
|
for (i = 0; i < members_dim; i++)
|
|
{
|
|
Dsymbol *s = (Dsymbol *)members->data[i];
|
|
s->semantic(sc);
|
|
}
|
|
|
|
if (sizeok == 2)
|
|
{ // semantic() failed because of forward references.
|
|
// Unwind what we did, and defer it for later
|
|
fields.setDim(0);
|
|
structsize = 0;
|
|
alignsize = 0;
|
|
structalign = 0;
|
|
|
|
sc = sc->pop();
|
|
|
|
scope = scx ? scx : new Scope(*sc);
|
|
scope->setNoFree();
|
|
scope->module->addDeferredSemantic(this);
|
|
|
|
//printf("\tsemantic('%s') failed due to forward references\n", toChars());
|
|
return;
|
|
}
|
|
|
|
//printf("\tsemantic('%s') successful\n", toChars());
|
|
|
|
structsize = sc->offset;
|
|
//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());
|
|
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?
|
|
sc->offset = structsize;
|
|
ctor->semantic(sc);
|
|
defaultCtor = ctor;
|
|
}
|
|
|
|
#if 0
|
|
if (baseClass)
|
|
{ if (!aggDelete)
|
|
aggDelete = baseClass->aggDelete;
|
|
if (!aggNew)
|
|
aggNew = baseClass->aggNew;
|
|
}
|
|
#endif
|
|
|
|
// Allocate instance of each new interface
|
|
for (i = 0; i < vtblInterfaces->dim; i++)
|
|
{
|
|
BaseClass *b = (BaseClass *)vtblInterfaces->data[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 = 1;
|
|
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 = (BaseClass *)vtblInterfaces->data[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 (int i = 0; i < baseclasses.dim; i++)
|
|
{
|
|
BaseClass *b = (BaseClass *)baseclasses.data[i];
|
|
|
|
if (i)
|
|
buf->writeByte(',');
|
|
//buf->writestring(b->base->ident->toChars());
|
|
b->type->toCBuffer(buf, NULL, hgs);
|
|
}
|
|
buf->writenl();
|
|
buf->writeByte('{');
|
|
buf->writenl();
|
|
for (int i = 0; i < members->dim; i++)
|
|
{
|
|
Dsymbol *s = (Dsymbol *)members->data[i];
|
|
|
|
buf->writestring(" ");
|
|
s->toCBuffer(buf, hgs);
|
|
}
|
|
buf->writestring("}");
|
|
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 (int i = 0; i < cd->baseclasses.dim; i++)
|
|
{ BaseClass *b = (BaseClass *)cd->baseclasses.data[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)
|
|
{
|
|
if (this == cd->baseClass)
|
|
return 1;
|
|
|
|
/* cd->baseClass might not be set if cd is forward referenced.
|
|
*/
|
|
if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
|
|
{
|
|
cd->error("base class is forward referenced by %s", toChars());
|
|
}
|
|
|
|
cd = cd->baseClass;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
|
|
{
|
|
Dsymbol *s;
|
|
|
|
//printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
|
|
if (scope)
|
|
semantic(scope);
|
|
|
|
if (!members || !symtab || scope)
|
|
{ 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
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < baseclasses.dim; i++)
|
|
{
|
|
BaseClass *b = (BaseClass *)baseclasses.data[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;
|
|
}
|
|
|
|
/**********************************************************
|
|
* 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;
|
|
}
|
|
s = s->toAlias();
|
|
OverloadSet *os = s->isOverloadSet();
|
|
if (os)
|
|
{
|
|
for (int i = 0; i < os->a.dim; i++)
|
|
{ Dsymbol *s = (Dsymbol *)os->a.data[i];
|
|
FuncDeclaration *f2 = s->isFuncDeclaration();
|
|
if (f2 && overloadApply(f2, &isf, fd))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
FuncDeclaration *fdstart = s->isFuncDeclaration();
|
|
//printf("%s fdstart = %p\n", s->kind(), fdstart);
|
|
return !overloadApply(fdstart, &isf, fd);
|
|
}
|
|
}
|
|
#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());
|
|
|
|
ClassDeclaration *cd = this;
|
|
Array *vtbl = &cd->vtbl;
|
|
while (1)
|
|
{
|
|
for (size_t i = 0; i < vtbl->dim; i++)
|
|
{
|
|
FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i];
|
|
|
|
//printf("\t[%d] = %s\n", i, fd->toChars());
|
|
if (ident == fd->ident &&
|
|
//tf->equals(fd->type)
|
|
fd->type->covariant(tf) == 1
|
|
)
|
|
{ //printf("\t\tfound\n");
|
|
return fd;
|
|
}
|
|
//else printf("\t\t%d\n", fd->type->covariant(tf));
|
|
}
|
|
if (!cd)
|
|
break;
|
|
vtbl = &cd->vtblFinal;
|
|
cd = cd->baseClass;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ClassDeclaration::interfaceSemantic(Scope *sc)
|
|
{
|
|
InterfaceDeclaration *id = isInterfaceDeclaration();
|
|
|
|
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;
|
|
|
|
if (b->base->isCPPinterface() && id)
|
|
id->cpp = 1;
|
|
|
|
vtblInterfaces->push(b);
|
|
b->copyBaseInterfaces(vtblInterfaces);
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
int ClassDeclaration::isCOMclass()
|
|
{
|
|
return com;
|
|
}
|
|
|
|
int ClassDeclaration::isCOMinterface()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int ClassDeclaration::isCPPinterface()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
int ClassDeclaration::isAbstract()
|
|
{
|
|
if (isabstract)
|
|
return TRUE;
|
|
for (int 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;
|
|
cpp = 0;
|
|
if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces
|
|
{ com = 1;
|
|
cpp = 1; // IUnknown is also a C++ interface
|
|
}
|
|
}
|
|
|
|
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)
|
|
{ int i;
|
|
|
|
//printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
|
|
if (inuse)
|
|
return;
|
|
if (!scope)
|
|
{ type = type->semantic(loc, sc);
|
|
handle = handle->semantic(loc, sc);
|
|
}
|
|
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 = 1;
|
|
}
|
|
|
|
// Expand any tuples in baseclasses[]
|
|
for (i = 0; i < baseclasses.dim; )
|
|
{ BaseClass *b = (BaseClass *)baseclasses.data[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 = Argument::dim(tup->arguments);
|
|
for (size_t j = 0; j < dim; j++)
|
|
{ Argument *arg = Argument::getNth(tup->arguments, j);
|
|
b = new BaseClass(arg->type, protection);
|
|
baseclasses.insert(i + j, b);
|
|
}
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
|
|
if (!baseclasses.dim && sc->linkage == LINKcpp)
|
|
cpp = 1;
|
|
|
|
// Check for errors, handle forward references
|
|
for (i = 0; i < baseclasses.dim; )
|
|
{ TypeClass *tc;
|
|
BaseClass *b;
|
|
Type *tb;
|
|
|
|
b = (BaseClass *)baseclasses.data[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())
|
|
{
|
|
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 = (BaseClass *)baseclasses.data[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 || 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;
|
|
}
|
|
}
|
|
#if 0
|
|
// Inherit const/invariant from base class
|
|
storage_class |= b->base->storage_class & (STCconst | STCinvariant);
|
|
#endif
|
|
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 (i = 0; i < interfaces_dim; i++)
|
|
{ BaseClass *b = interfaces[i];
|
|
|
|
// Skip if b has already appeared
|
|
for (int k = 0; k < i; k++)
|
|
{
|
|
if (b == interfaces[i])
|
|
goto Lcontinue;
|
|
}
|
|
|
|
// Copy vtbl[] from base class
|
|
if (b->base->vtblOffset())
|
|
{ int d = b->base->vtbl.dim;
|
|
if (d > 1)
|
|
{
|
|
vtbl.reserve(d - 1);
|
|
for (int j = 1; j < d; j++)
|
|
vtbl.push(b->base->vtbl.data[j]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vtbl.append(&b->base->vtbl);
|
|
}
|
|
|
|
Lcontinue:
|
|
;
|
|
}
|
|
|
|
protection = sc->protection;
|
|
storage_class |= sc->stc & (STCconst | STCinvariant);
|
|
|
|
for (i = 0; i < members->dim; i++)
|
|
{
|
|
Dsymbol *s = (Dsymbol *)members->data[i];
|
|
s->addMember(sc, this, 1);
|
|
}
|
|
|
|
sc = sc->push(this);
|
|
sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
|
|
STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
|
|
sc->stc |= storage_class & (STCconst | STCinvariant);
|
|
sc->parent = this;
|
|
if (isCOMinterface())
|
|
sc->linkage = LINKwindows;
|
|
else if (isCPPinterface())
|
|
sc->linkage = LINKcpp;
|
|
sc->structalign = 8;
|
|
structalign = sc->structalign;
|
|
sc->offset = PTRSIZE * 2;
|
|
inuse++;
|
|
for (i = 0; i < members->dim; i++)
|
|
{
|
|
Dsymbol *s = (Dsymbol *)members->data[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;
|
|
}
|
|
return 1;
|
|
}
|
|
if (isBaseOf(b, poffset))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
if (poffset)
|
|
*poffset = 0;
|
|
return 0;
|
|
}
|
|
|
|
/****************************************
|
|
* 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() || isCPPinterface())
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int InterfaceDeclaration::isCOMinterface()
|
|
{
|
|
return com;
|
|
}
|
|
|
|
int InterfaceDeclaration::isCPPinterface()
|
|
{
|
|
return cpp;
|
|
}
|
|
|
|
/*******************************************
|
|
*/
|
|
|
|
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, Array *vtbl, int newinstance)
|
|
{
|
|
ClassDeclaration *id = base;
|
|
int j;
|
|
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 (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");
|
|
}
|