view dmd/class.c @ 650:aa6a0b7968f7

Added test case for bug #100 Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sun, 05 Oct 2008 17:28:15 +0200
parents aaade6ded589
children 50383e476c7e
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 "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;

    ctor = NULL;
    defaultCtor = NULL;
    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
    {	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())
		error("super class %s is nested within %s, not %s",
			baseClass->toChars(),
			baseClass->toParent2()->toChars(),
			toParent2()->toChars());
	}
	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())
	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 = 8;		// allow room for vptr[] and monitor
	alignsize = 4;
    }
    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 = 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 = (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)
{
    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 = 8;
    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");
}