Mercurial > projects > ldc
view dmd/class.c @ 1168:ab186e535e72
A different fix to #218 and DMD2682 that does not lead to constant folding regressions.
Fixes run/const_15, run/c/const_16_B.
The price is removing the lvalueness of struct literals. If it turns out too
much code depends on this behavior or we don't want to break with DMD, we
could keep struct literals as lvalues and instead convert struct literals used
as expression initializers into struct initializers.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Sun, 29 Mar 2009 11:43:45 +0200 |
parents | 1860414bf3b7 |
children | e961851fb8be |
line wrap: on
line source
// 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 "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(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; 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::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 { 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; } // 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; } 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; sc = sc->push(this); sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated); 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 = 2*PTRSIZE; // 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(%s)\n", 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); 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 = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); if (!fd) continue; // the first entry might be a ClassInfo //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) { 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; } /**************************************** */ 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; 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) { 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++; } // 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; } } 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: ; } for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->addMember(sc, this, 1); } sc = sc->push(this); sc->parent = this; if (isCOMinterface()) sc->linkage = LINKwindows; sc->structalign = 8; structalign = sc->structalign; sc->offset = 2*PTRSIZE; 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()) return 0; return 1; } int InterfaceDeclaration::isCOMinterface() { return com; } /******************************************* */ 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"); }