// 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 #include #include #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"); }