view dmd/ClassDeclaration.d @ 135:af1bebfd96a4 dmd2037

dmd 2.038
author Eldar Insafutdinov <e.insafutdinov@gmail.com>
date Mon, 13 Sep 2010 22:19:42 +0100
parents 60bb0fe4563e
children 90821c10b6a7
line wrap: on
line source

module dmd.ClassDeclaration;

import dmd.common;
import dmd.AggregateDeclaration;
import dmd.InterfaceDeclaration;
import dmd.ThisDeclaration;
import dmd.CompoundStatement;
import dmd.DeleteDeclaration;
import dmd.NewDeclaration;
import dmd.CtorDeclaration;
import dmd.TypeIdentifier;
import dmd.STC;
import dmd.Parameter;
import dmd.TypeTuple;
import dmd.TY;
import dmd.LINK;
import dmd.DsymbolTable;
import dmd.FuncDeclaration;
import dmd.Array;
import dmd.TypeClass;
import dmd.Module;
import dmd.Id;
import dmd.Type;
import dmd.OverloadSet;
import dmd.ArrayTypes;
import dmd.BaseClass;
import dmd.ClassInfoDeclaration;
import dmd.TypeInfoClassDeclaration;
import dmd.Loc;
import dmd.Identifier;
import dmd.Dsymbol;
import dmd.Scope;
import dmd.TypeFunction;
import dmd.OutBuffer;
import dmd.HdrGenState;
import dmd.VarDeclaration;
import dmd.Initializer;
import dmd.ExpInitializer;
import dmd.TypeSArray;
import dmd.ScopeDsymbol;
import dmd.PROT;
import dmd.Util;
import dmd.Global;

import dmd.expression.Util;

import dmd.backend.Symbol;
import dmd.backend.dt_t;
import dmd.backend.TYPE;
import dmd.backend.FL;
import dmd.backend.SFL;
import dmd.backend.mTY;
import dmd.backend.SC;
import dmd.backend.mTYman;
import dmd.backend.Util;
import dmd.backend.TYM;
import dmd.backend.Classsym;
import dmd.backend.glue;
import dmd.backend.RTLSYM;
import dmd.backend.LIST;

import dmd.codegen.Util;

import std.string;

version (DMDV2) {
	enum CLASSINFO_SIZE = (0x3C+12+4);	// value of ClassInfo.size
} else {
	enum CLASSINFO_SIZE = (0x3C+12+4);	// value of ClassInfo.size
}

enum OFFSET_RUNTIME = 0x76543210;

struct Param
{
	int isf(void*, FuncDeclaration fd2)
	{
		//printf("param = %p, fd = %p %s\n", param, fd, fd.toChars());
		return fd is fd2;
	}
	
	FuncDeclaration fd;
}

class ClassDeclaration : AggregateDeclaration
{
    static __gshared ClassDeclaration object;
    static __gshared ClassDeclaration classinfo;

    ClassDeclaration baseClass;	// null only if this is Object
version(DMDV1) {
    CtorDeclaration *ctor;
    CtorDeclaration *defaultCtor;	// default constructor
}
    FuncDeclaration staticCtor;
    FuncDeclaration staticDtor;
    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]

    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
					// rest are Interface's

    int interfaces_dim;
    BaseClass* interfaces;		// interfaces[interfaces_dim] for this class
					// (does not include baseClass)

    BaseClasses vtblInterfaces;	// array of base interfaces that have
					// their own vtbl[]

    TypeInfoClassDeclaration vclassinfo;	// the ClassInfo object for this ClassDeclaration
    bool com;				// true if this is a COM class (meaning
					// it derives from IUnknown)
    bool isauto;				// true if this is an auto class
    bool isabstract;			// true if abstract class
version(DMDV1) {
    int isnested;			// !=0 if is nested
}
    int inuse;				// to prevent recursive attempts

    this(Loc loc, Identifier id, BaseClasses baseclasses)
	{
		super(loc, id);
		
		vtbl = new Array();
		vtblFinal = new Array();
		
		enum msg = "only object.d can define this reserved class name";

		if (baseclasses) {
			this.baseclasses = baseclasses;
		} else {
			this.baseclasses = new BaseClasses();
		}

		//printf("ClassDeclaration(%s), dim = %d\n", id.toChars(), this.baseclasses.dim);

		// For forward references
		type = new TypeClass(this);

		if (id)
		{
			// Look for special class names

			if (id is Id.__sizeof || id is Id.alignof_ || id is 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 is Id.TypeInfo)
				{	
					if (Type.typeinfo)
						Type.typeinfo.error("%s", msg);
					Type.typeinfo = this;
				}

				if (id is Id.TypeInfo_Class)
				{	
					if (Type.typeinfoclass)
						Type.typeinfoclass.error("%s", msg);
					Type.typeinfoclass = this;
				}

				if (id is Id.TypeInfo_Interface)
				{	
					if (Type.typeinfointerface)
						Type.typeinfointerface.error("%s", msg);
					Type.typeinfointerface = this;
				}

				if (id is Id.TypeInfo_Struct)
				{	
					if (Type.typeinfostruct)
						Type.typeinfostruct.error("%s", msg);
					Type.typeinfostruct = this;
				}

				if (id is Id.TypeInfo_Typedef)
				{	
					if (Type.typeinfotypedef)
						Type.typeinfotypedef.error("%s", msg);
					Type.typeinfotypedef = this;
				}

				if (id is Id.TypeInfo_Pointer)
				{	
					if (Type.typeinfopointer)
						Type.typeinfopointer.error("%s", msg);
					Type.typeinfopointer = this;
				}

				if (id is Id.TypeInfo_Array)
				{	
					if (Type.typeinfoarray)
						Type.typeinfoarray.error("%s", msg);
					Type.typeinfoarray = this;
				}

				if (id is Id.TypeInfo_StaticArray)
				{	//if (Type.typeinfostaticarray)
					//Type.typeinfostaticarray.error("%s", msg);
					Type.typeinfostaticarray = this;
				}

				if (id is Id.TypeInfo_AssociativeArray)
				{	
					if (Type.typeinfoassociativearray)
						Type.typeinfoassociativearray.error("%s", msg);
					Type.typeinfoassociativearray = this;
				}

				if (id is Id.TypeInfo_Enum)
				{	
					if (Type.typeinfoenum)
						Type.typeinfoenum.error("%s", msg);
					Type.typeinfoenum = this;
				}

				if (id is Id.TypeInfo_Function)
				{	
					if (Type.typeinfofunction)
						Type.typeinfofunction.error("%s", msg);
					Type.typeinfofunction = this;
				}

				if (id is Id.TypeInfo_Delegate)
				{	
					if (Type.typeinfodelegate)
						Type.typeinfodelegate.error("%s", msg);
					Type.typeinfodelegate = this;
				}

				if (id is Id.TypeInfo_Tuple)
				{	
					if (Type.typeinfotypelist)
						Type.typeinfotypelist.error("%s", msg);
					Type.typeinfotypelist = this;
				}

	version (DMDV2) {
				if (id is Id.TypeInfo_Const)
				{	
					if (Type.typeinfoconst)
						Type.typeinfoconst.error("%s", msg);
					Type.typeinfoconst = this;
				}

				if (id is Id.TypeInfo_Invariant)
				{	
					if (Type.typeinfoinvariant)
						Type.typeinfoinvariant.error("%s", msg);
					Type.typeinfoinvariant = this;
				}

				if (id is Id.TypeInfo_Shared)
				{	
					if (Type.typeinfoshared)
						Type.typeinfoshared.error("%s", msg);
					Type.typeinfoshared = this;
				}

	            if (id == Id.TypeInfo_Wild)
	            {
                    if (Type.typeinfowild)
		                Type.typeinfowild.error("%s", msg);
		            Type.typeinfowild = this;
	            }
	}
			}

			if (id is Id.Object_)
			{   
				if (object)
					object.error("%s", msg);
				object = this;
			}

//			if (id is Id.ClassInfo)
			if (id is Id.TypeInfo_Class)
			{   
				if (classinfo)
					classinfo.error("%s", msg);
				classinfo = this;
			}

			if (id is Id.ModuleInfo)
			{   
				if (Module.moduleinfo)
					Module.moduleinfo.error("%s", msg);
				Module.moduleinfo = this;
			}
		}

		com = 0;
		isauto = false;
		isabstract = false;
		inuse = 0;
	}
	
    override Dsymbol syntaxCopy(Dsymbol s)
	{
		ClassDeclaration cd;

		//printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
		if (s)
			cd = cast(ClassDeclaration)s;
		else
		cd = new ClassDeclaration(loc, ident, null);

		cd.storage_class |= storage_class;

		cd.baseclasses.setDim(this.baseclasses.dim);
		for (size_t i = 0; i < cd.baseclasses.dim; i++)
		{
			auto b = this.baseclasses[i];
			auto b2 = new BaseClass(b.type.syntaxCopy(), b.protection);
			cd.baseclasses[i] = b2;
		}

		ScopeDsymbol.syntaxCopy(cd);
		return cd;
	}
	
    override void semantic(Scope sc)
	{
		uint 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
		{	
			string id = "__anonclass";
			ident = Identifier.generateId(id);
		}

		if (!sc)
			sc = scope_;

		if (!parent && sc.parent && !sc.parent.isModule())
			parent = sc.parent;

		type = type.semantic(loc, sc);
		handle = type;

		if (!members)			// if forward reference
		{	
			//printf("\tclass '%s' is forward referenced\n", toChars());
			return;
		}
		if (symtab)
		{	if (!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;
		}
version (IN_GCC) {
		methods.setDim(0);
}

		if (sc.stc & STC.STCdeprecated)
		{
		isdeprecated = 1;
		}

		if (sc.linkage == LINK.LINKcpp)
		error("cannot create C++ classes");

		// Expand any tuples in baseclasses[]
		for (size_t i = 0; i < baseclasses.dim; )
		{	
			auto b = baseclasses[i];
		//printf("test1 %s %s\n", toChars(), b.type.toChars());
			b.type = b.type.semantic(loc, sc);
		//printf("test2\n");
			Type tb = b.type.toBasetype();

			if (tb.ty == TY.Ttuple)
			{   
				TypeTuple tup = cast(TypeTuple)tb;
				enum PROT protection = b.protection;
				baseclasses.remove(i);
				size_t dim = Parameter.dim(tup.arguments);
				for (size_t j = 0; j < dim; j++)
				{	
					auto arg = Parameter.getNth(tup.arguments, j);
					b = new BaseClass(arg.type, protection);
					baseclasses.insert(i + j, b);
				}
			}
			else
				i++;
		}

		// See if there's a base class as first in baseclasses[]
		if (baseclasses.dim)
		{	
			TypeClass tc;
			BaseClass b;
			Type tb;

			b = baseclasses[0];
			//b.type = b.type.semantic(loc, sc);
			tb = b.type.toBasetype();
			if (tb.ty != TY.Tclass)
			{   error("base type must be class or interface, not %s", b.type.toChars());
				baseclasses.remove(0);
			}
			else
			{
				tc = cast(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.sizeok == 0)
					{   // Try to resolve forward reference
						if (sc.mustsemantic && tc.sym.scope_)
						tc.sym.semantic(null);
					}
					if (!tc.sym.symtab || tc.sym.scope_ || tc.sym.sizeok == 0)
					{
						//printf("%s: forward reference of base class %s\n", toChars(), tc.sym.toChars());
						//error("forward reference of base class %s", baseClass.toChars());
						// Forward reference of base class, try again later
						//printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars());
						scope_ = scx ? scx : sc.clone();
						scope_.setNoFree();
						if (tc.sym.scope_)
							tc.sym.scope_.module_.addDeferredSemantic(tc.sym);
						scope_.module_.addDeferredSemantic(this);
						return;
					}
					else
					{   baseClass = tc.sym;
						b.base = baseClass;
					}
				 L7: ;
				}
			}
		}

		// Treat the remaining entries in baseclasses as interfaces
		// Check for errors, handle forward references
		for (int i = (baseClass ? 1 : 0); i < baseclasses.dim; )
		{	TypeClass tc;
		BaseClass b;
		Type tb;

		b = baseclasses[i];
		b.type = b.type.semantic(loc, sc);
		tb = b.type.toBasetype();
		if (tb.ty == TY.Tclass)
			tc = cast(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++)
			{
			auto b2 = baseclasses[j];
			if (b2.base == tc.sym)
				error("inherits from duplicate interface %s", b2.base.toChars());
			}

			if (!tc.sym.symtab)
			{   // Try to resolve forward reference
			if (sc.mustsemantic && tc.sym.scope_)
				tc.sym.semantic(null);
			}

			b.base = tc.sym;
			if (!b.base.symtab || b.base.scope_)
			{
			//error("forward reference of base class %s", baseClass.toChars());
			// Forward reference of base, try again later
			//printf("\ttry later, forward reference of base %s\n", baseClass.toChars());
			scope_ = scx ? scx : sc.clone();
			scope_.setNoFree();
			if (tc.sym.scope_)
				tc.sym.scope_.module_.addDeferredSemantic(tc.sym);
			scope_.module_.addDeferredSemantic(this);
			return;
			}
		}
		i++;
		}


		// If no base class, and this is not an Object, use Object as base class
		if (!baseClass && ident !is Id.Object_)
		{
			// BUG: what if Object is redefined in an inner scope?
			Type tbase = new TypeIdentifier(Loc(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, PROT.PROTpublic);
			baseclasses.shift(b);
			assert(b.type.ty == TY.Tclass);
			tc = cast(TypeClass)(b.type);
			baseClass = tc.sym;
			assert(!baseClass.isInterfaceDeclaration());
			b.base = baseClass;
		}

		interfaces_dim = baseclasses.dim;
		interfaces = baseclasses.ptr;

		if (baseClass)
		{
			if (baseClass.storage_class & STC.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, (void*).sizeof * vtbl.dim);

			// Inherit properties from base class
			com = baseClass.isCOMclass();
			isauto = baseClass.isauto;
			vthis = baseClass.vthis;
			storage_class |= baseClass.storage_class & STC.STC_TYPECTOR;
		}
		else
		{
			// No base class, so this is the root of the class hierarchy
			vtbl.setDim(0);
			vtbl.push(cast(void*)this);		// leave room for classinfo as first member
		}

		protection = sc.protection;
		storage_class |= sc.stc;

		if (sizeok == 0)
		{
		interfaceSemantic(sc);

		foreach (s; members)
			s.addMember(sc, this, true);

		/* 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 = true;
			if (storage_class & STC.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 = false;
			}
		}
		else if (!(storage_class & STC.STCstatic))
		{   
			Dsymbol s = toParent2();
			if (s)
			{
				AggregateDeclaration ad = s.isClassDeclaration();
				FuncDeclaration fd = s.isFuncDeclaration();

				if (ad || fd)
				{   isnested = true;
					Type t;
					if (ad)
						t = ad.handle;
					else if (fd)
					{	
						AggregateDeclaration ad2 = fd.isMember2();
						if (ad2)
							t = ad2.handle;
						else
						{
							t = Type.tvoidptr;
						}
					}
					else
						assert(0);
					if (t.ty == TY.Tstruct)	// ref to struct
						t = Type.tvoidptr;
					assert(!vthis);
					vthis = new ThisDeclaration(loc, t);
					members.push(vthis);
				}
			}
		}
		}

		if (storage_class & (STC.STCauto | STC.STCscope))
			isauto = true;
		if (storage_class & STC.STCabstract)
			isabstract = true;
		if (storage_class & STC.STCimmutable)
			type = type.invariantOf();
		else if (storage_class & STC.STCconst)
			type = type.constOf();
		else if (storage_class & STC.STCshared)
			type = type.sharedOf();

		sc = sc.push(this);
		sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic |
			 STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared);
		sc.stc |= storage_class & STC.STC_TYPECTOR;
		sc.parent = this;
		sc.inunion = 0;

		if (isCOMclass())
		{
version (Windows) {
		sc.linkage = LINK.LINKwindows;
} else {
		/* This enables us to use COM objects under Linux and
		 * work with things like XPCOM
		 */
		sc.linkage = LINK.LINKc;
}
		}
		sc.protection = PROT.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.clone();
		sizeok = 0;

        /* Set scope so if there are forward references, we still might be able to
         * resolve individual members like enums.
         */
        foreach (s; members)
        {
	        /* There are problems doing this in the general case because
	         * Scope keeps track of things like 'offset'
	         */
	        if (s.isEnumDeclaration() || (s.isAggregateDeclaration() && s.ident))
	        {
	            //printf("setScope %s %s\n", s->kind(), s->toChars());
	            s.setScope(sc);
	        }
        }
            
		foreach (Dsymbol s; members) {
			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 : sc.clone();
		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 = cast(CtorDeclaration)search(Loc(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 = cast(NewDeclaration)search(Loc(0), Id.classNew, 0);
		aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0);

		// If this class has no constructor, but base class does, create
		// a constructor:
		//    this() { }
		if (!ctor && baseClass && baseClass.ctor)
		{
		//printf("Creating default this(){} for class %s\n", toChars());
		CtorDeclaration ctor = new CtorDeclaration(loc, Loc(0), null, 0);
		ctor.fbody = new CompoundStatement(Loc(0), new Statements());
		members.push(ctor);
		ctor.addMember(sc, this, true);
		sc = scsave;	// why? What about sc.nofree?	///
		sc.offset = structsize;
		ctor.semantic(sc);
		this.ctor = ctor;
		defaultCtor = ctor;
		}

static if (false) {
		if (baseClass)
		{	if (!aggDelete)
			aggDelete = baseClass.aggDelete;
		if (!aggNew)
			aggNew = baseClass.aggNew;
		}
}

		// Allocate instance of each new interface
		foreach (b; vtblInterfaces)
		{
			uint thissize = PTRSIZE;

			alignmember(structalign, thissize, &sc.offset);
			assert(b.offset == 0);
			b.offset = sc.offset;

			// Take care of single inheritance offsets
			while (b.baseInterfaces.length)
			{
				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();

static if (false) { // Do not call until toObjfile() because of forward references
		// Fill in base class vtbl[]s
		for (int i = 0; i < vtblInterfaces.dim; i++)
		{
			BaseClass b = cast(BaseClass)vtblInterfaces.data[i];

		//b.fillVtbl(this, &b.vtbl, 1);
		}
}
		//printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
	}
	
    override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		if (!isAnonymous())
		{
			buf.printf("%s ", kind());
			buf.writestring(toChars());
			if (baseclasses.dim)
				buf.writestring(" : ");
		}
		foreach (size_t i, BaseClass b; baseclasses)
		{
			if (i)
				buf.writeByte(',');
			//buf.writestring(b.base.ident.toChars());
			b.type.toCBuffer(buf, null, hgs);
		}
		if (members)
		{
			buf.writenl();
			buf.writeByte('{');
			buf.writenl();
			foreach (s; members)
			{
				buf.writestring("    ");
				s.toCBuffer(buf, hgs);
			}
			buf.writestring("}");
		}
		else
			buf.writeByte(';');
		buf.writenl();
	}
	
	/*********************************************
	 * Determine if 'this' is a base class of cd.
	 * This is used to detect circular inheritance only.
	 */
    int isBaseOf2(ClassDeclaration cd)
	{
		if (!cd)
			return 0;
		//printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
		foreach (b; cd.baseclasses)
		{	
			if (b.base is this || isBaseOf2(b.base))
				return 1;
		}
		return 0;
	}

	/*******************************************
	 * Determine if 'this' is a base class of cd.
	 */
///    #define OFFSET_RUNTIME 0x76543210
    bool isBaseOf(ClassDeclaration cd, int* poffset)
	{
		if (!cd)
			return 0;
		//printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
		foreach (b; cd.baseclasses)
		{	
			if (b.base == this || isBaseOf2(b.base))
				return 1;
		}

		return 0;
	}

    override Dsymbol search(Loc, Identifier ident, int flags)
	{
		Dsymbol s;
		//printf("%s.ClassDeclaration.search('%s')\n", toChars(), ident.toChars());

		if (scope_)
		{
			Scope sc = scope_;
			sc.mustsemantic++;
			semantic(sc);
			sc.mustsemantic--;
		}

		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;

			foreach (b; baseclasses)
			{
				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 is this)	// happens if s is nested in this and derives from this
							s = null;
						else if (s)
							break;
					}
				}
			}
		}
		return s;
	}
	
version (DMDV2) {
    bool isFuncHidden(FuncDeclaration fd)
	{
		//printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toChars());
		Dsymbol s = search(Loc(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 false;
		}
		
		Param p; p.fd = fd;

		s = s.toAlias();
		OverloadSet os = s.isOverloadSet();	
		if (os)
		{
			foreach (s2; os.a)
			{   
				auto f2 = s2.isFuncDeclaration();
				if (f2 && overloadApply(f2, &p.isf, &p))
					return false;
			}
			return true;
		}
		else
		{
			FuncDeclaration fdstart = s.isFuncDeclaration();
			//printf("%s fdstart = %p\n", s.kind(), fdstart);
			return !overloadApply(fdstart, &p.isf, &p);
		}
	}
}
    FuncDeclaration 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 (true)
		{
			for (size_t i = 0; i < vtbl.dim; i++)
			{
				FuncDeclaration fd = (cast(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 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);
		}
	}

version(DMDV1)
{
    int isNested()
	{
		assert(false);
	}
}
    bool isCOMclass()
	{
		return com;
	}
	
    bool isCOMinterface()
	{
		return false;
	}

version (DMDV2) {
    bool isCPPinterface()
	{
		return false;
	}
}
    bool isAbstract()
	{
		if (isabstract)
			return true;

		for (int i = 1; i < vtbl.dim; i++)
		{
			FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration();

			//printf("\tvtbl[%d] = %p\n", i, fd);
			if (!fd || fd.isAbstract())
			{
				isabstract = true;
				return true;
			}
		}

		return false;
	}
	
    int vtblOffset()
	{
		assert(false);
	}
	
    override string kind()
	{
		return "class";
	}
	
    override string mangle()
	{
		Dsymbol parentsave = parent;

		//printf("ClassDeclaration.mangle() %s.%s\n", parent.toChars(), toChars());

		/* These are reserved to the compiler, so keep simple
		 * names for them.
		 */
		if (ident is Id.Exception)
		{	
			if (parent.ident is Id.object)
				parent = null;
		}
		else if (ident is Id.TypeInfo   ||
		//	ident is Id.Exception ||
			ident is Id.TypeInfo_Struct   ||
			ident is Id.TypeInfo_Class    ||
			ident is Id.TypeInfo_Typedef  ||
			ident is Id.TypeInfo_Tuple ||
			this is object     ||
			this is classinfo  ||
			this is Module.moduleinfo ||
			ident.toChars().startsWith("TypeInfo_")
		   )
		{
			parent = null;
		}

		string id = Dsymbol.mangle();
		parent = parentsave;
		return id;
	}
	
    override void toDocBuffer(OutBuffer buf)
	{
		assert(false);
	}

    override PROT getAccess(Dsymbol smember)	// determine access to smember
	{
		PROT access_ret = PROT.PROTnone;

	version (LOG) {
		printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
			toChars(), smember.toChars());
	}
		if (smember.toParent() is this)
		{
			access_ret = smember.prot();
		}
		else
		{
			PROT access;

			if (smember.isDeclaration().isStatic())
			{
				access_ret = smember.prot();
			}

			foreach (b; baseclasses)
			{   
				access = b.base.getAccess(smember);
				switch (access)
				{
					case PROT.PROTnone:
						break;

					case PROT.PROTprivate:
						access = PROT.PROTnone;	// private members of base class not accessible
						break;

					case PROT.PROTpackage:
					case PROT.PROTprotected:
					case PROT.PROTpublic:
					case PROT.PROTexport:
						// If access is to be tightened
						if (b.protection < access)
							access = b.protection;

						// Pick path with loosest access
						if (access > access_ret)
							access_ret = access;
						break;

					default:
						assert(0);
				}
			}
		}

	version (LOG) {
		printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
			toChars(), smember.toChars(), access_ret);
	}

		return access_ret;
	}

    override void addLocalClass(ClassDeclarations aclasses)
	{
		aclasses.push(this);
	}

    // Back end
    override void toObjFile(int multiobj)			// compile to .obj file
	{
		uint offset;
		Symbol* sinit;
		enum_SC scclass;

		//printf("ClassDeclaration.toObjFile('%s')\n", toChars());

		if (!members)
			return;

		if (multiobj)
		{	
			obj_append(this);
			return;
		}

		if (global.params.symdebug)
			toDebug();

		assert(!scope_);	// semantic() should have been run to completion

		scclass = SCglobal;
		if (inTemplateInstance())
			scclass = SCcomdat;

		// Put out the members
		foreach (member; members)
			member.toObjFile(0);

static if (false) {
		// Build destructor by aggregating dtors[]
		Symbol* sdtor;
		switch (dtors.dim)
		{	
			case 0:
				// No destructors for this class
				sdtor = null;
				break;

			case 1:
				// One destructor, just use it directly
				sdtor = (cast(DtorDeclaration)dtors.data[0]).toSymbol();
				break;

			default:
			{   
				/* Build a destructor that calls all the
				 * other destructors in dtors[].
				 */

				elem* edtor = null;

				// Declare 'this' pointer for our new destructor
				Symbol* sthis = symbol_calloc("this");
				sthis.Stype = type_fake(TYnptr);
				sthis.Stype.Tcount++;
				sthis.Sclass = SCfastpar;
				sthis.Spreg = AX;
				sthis.Sfl = FLauto;

				// Call each of the destructors in dtors[]
				// in reverse order
				for (size_t i = 0; i < dtors.dim; i++)
				{	
					DtorDeclaration d = cast(DtorDeclaration)dtors.data[i];
					Symbol* s = d.toSymbol();
					elem* e = el_bin(OPcall, TYvoid, el_var(s), el_var(sthis));
					edtor = el_combine(e, edtor);
				}

				// Create type for the function
				.type* t = type_alloc(TYjfunc);
				t.Tflags |= TFprototype | TFfixed;
				t.Tmangle = mTYman_d;
				t.Tnext = tsvoid;
				tsvoid.Tcount++;

				// Create the function, sdtor, and write it out
				localgot = null;
				sdtor = toSymbolX("__dtor", SCglobal, t, "FZv");
				block* b = block_calloc();
				b.BC = BCret;
				b.Belem = edtor;
				sdtor.Sfunc.Fstartblock = b;
				cstate.CSpsymtab = &sdtor.Sfunc.Flocsym;
				symbol_add(sthis);
				writefunc(sdtor);
			}
		}
}

		// Generate C symbols
		toSymbol();
		toVtblSymbol();
		sinit = toInitializer();

		//////////////////////////////////////////////

		// Generate static initializer
		sinit.Sclass = scclass;
		sinit.Sfl = FLdata;
	version (ELFOBJ) { // Burton
		sinit.Sseg = Segment.CDATA;
	}
	version (MACHOBJ) {
		sinit.Sseg = Segment.DATA;
	}
		toDt(&sinit.Sdt);
		outdata(sinit);

		//////////////////////////////////////////////

		// Put out the TypeInfo
		type.getTypeInfo(null);
		//type.vtinfo.toObjFile(multiobj);

		//////////////////////////////////////////////

		// Put out the ClassInfo
		csym.Sclass = scclass;
		csym.Sfl = FLdata;

		/* The layout is:
		   {
			void **vptr;
			monitor_t monitor;
			byte[] initializer;		// static initialization data
			char[] name;		// class name
			void *[] vtbl;
			Interface[] interfaces;
			ClassInfo *base;		// base class
			void *destructor;
			void *invariant;		// class invariant
			uint flags;
			void *deallocator;
			OffsetTypeInfo[] offTi;
			void *defaultConstructor;
			const(MemberInfo[]) function(string) xgetMembers;	// module getMembers() function
			//TypeInfo typeinfo;
		   }
		 */
		dt_t* dt = null;
		offset = CLASSINFO_SIZE;			// must be ClassInfo.size
		if (classinfo)
		{
			if (classinfo.structsize != CLASSINFO_SIZE)
				error("D compiler and phobos' object.d are mismatched");
		}

		if (classinfo)
			dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo
		else
			dtdword(&dt, 0);		// BUG: should be an assert()

		dtdword(&dt, 0);			// monitor

		// initializer[]
		assert(structsize >= 8);
		dtdword(&dt, structsize);		// size
		dtxoff(&dt, sinit, 0, TYnptr);	// initializer

		// name[]
		string name = ident.toChars();
		size_t namelen = name.length;
		if (!(namelen > 9 && name[0..9] == "TypeInfo_"))
		{	
			name = toPrettyChars();
			namelen = name.length;
		}
		dtdword(&dt, namelen);
		dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name));

		// vtbl[]
		dtdword(&dt, vtbl.dim);
		dtxoff(&dt, vtblsym, 0, TYnptr);

		// interfaces[]
		dtdword(&dt, vtblInterfaces.dim);
		if (vtblInterfaces.dim)
			dtxoff(&dt, csym, offset, TYnptr);	// (*)
		else
			dtdword(&dt, 0);

		// base
		if (baseClass)
			dtxoff(&dt, baseClass.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);

		// destructor
		if (dtor)
			dtxoff(&dt, dtor.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);

		// invariant
		if (inv)
			dtxoff(&dt, inv.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);

		// flags
		int flags = 4 | isCOMclass();
	version (DMDV2) {
		flags |= 16;
	}
		flags |= 32;

		if (ctor)
			flags |= 8;
		for (ClassDeclaration cd = this; cd; cd = cd.baseClass)
		{
			if (cd.members)
			{
				foreach (sm; cd.members)
				{
					//printf("sm = %s %s\n", sm.kind(), sm.toChars());
					if (sm.hasPointers())
						goto L2;
				}
			}
		}
		flags |= 2;			// no pointers
	  L2:
		dtdword(&dt, flags);


		// deallocator
		if (aggDelete)
			dtxoff(&dt, aggDelete.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);

		// offTi[]
		dtdword(&dt, 0);
		dtdword(&dt, 0);		// null for now, fix later

		// defaultConstructor
		if (defaultCtor)
			dtxoff(&dt, defaultCtor.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);

	version (DMDV2) {
		FuncDeclaration sgetmembers = findGetMembers();
		if (sgetmembers)
			dtxoff(&dt, sgetmembers.toSymbol(), 0, TYnptr);
		else
			dtdword(&dt, 0);	// module getMembers() function
	}

		//dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr);	// typeinfo
		//dtdword(&dt, 0);

		//////////////////////////////////////////////

		// Put out vtblInterfaces.data[]. Must immediately follow csym, because
		// of the fixup (*)

		offset += vtblInterfaces.dim * (4 * PTRSIZE);
		foreach (b; vtblInterfaces)
		{	
			ClassDeclaration id = b.base;

			/* The layout is:
	         *  struct Interface
             *  {
			 *	ClassInfo *interface;
			 *	void *[] vtbl;
			 *	ptrdiff_t offset;
			 *  }
			 */

			// Fill in vtbl[]
			b.fillVtbl(this, b.vtbl, 1);

			dtxoff(&dt, id.toSymbol(), 0, TYnptr);		// ClassInfo

			// vtbl[]
			dtdword(&dt, id.vtbl.dim);
			dtxoff(&dt, csym, offset, TYnptr);

			dtdword(&dt, b.offset);			// this offset

			offset += id.vtbl.dim * PTRSIZE;
		}

		// Put out the vtblInterfaces.data[].vtbl[]
		// This must be mirrored with ClassDeclaration.baseVtblOffset()
		//printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars());
		foreach (size_t i, BaseClass b; vtblInterfaces)
		{	
			ClassDeclaration id = b.base;
			int j;

			//printf("    interface[%d] is '%s'\n", i, id.toChars());
			j = 0;
			if (id.vtblOffset())
			{
				// First entry is ClassInfo reference
				//dtxoff(&dt, id.toSymbol(), 0, TYnptr);

				// First entry is struct Interface reference
				dtxoff(&dt, csym, CLASSINFO_SIZE + i * (4 * PTRSIZE), TYnptr);
				j = 1;
			}
			
			assert(id.vtbl.dim == b.vtbl.dim);
			for (; j < id.vtbl.dim; j++)
			{
				assert(j < b.vtbl.dim);
		static if (false) {
				Object o = cast(Object)b.vtbl.data[j];
				if (o)
				{
					printf("o = %p\n", o);
					assert(o.dyncast() == DYNCAST_DSYMBOL);
					Dsymbol s = cast(Dsymbol)o;
					printf("s.kind() = '%s'\n", s.kind());
				}
		}
				auto fd = cast(FuncDeclaration)b.vtbl.data[j];
				if (fd)
					dtxoff(&dt, fd.toThunkSymbol(b.offset), 0, TYnptr);
				else
					dtdword(&dt, 0);
			}
		}

	static if (true) {
		// Put out the overriding interface vtbl[]s.
		// This must be mirrored with ClassDeclaration.baseVtblOffset()
		//printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
		ClassDeclaration cd;
		scope Array bvtbl = new Array();

		for (cd = this.baseClass; cd; cd = cd.baseClass)
		{
			foreach (size_t k, BaseClass bs; cd.vtblInterfaces)
			{   
				if (bs.fillVtbl(this, bvtbl, 0))
				{
					//printf("\toverriding vtbl[] for %s\n", bs.base.toChars());
					ClassDeclaration id = bs.base;
					int j;

					j = 0;
					if (id.vtblOffset())
					{
						// First entry is ClassInfo reference
						//dtxoff(&dt, id.toSymbol(), 0, TYnptr);

						// First entry is struct Interface reference
						dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr);
						j = 1;
					}

					for (; j < id.vtbl.dim; j++)
					{
						assert(j < bvtbl.dim);
						FuncDeclaration fd = cast(FuncDeclaration)bvtbl.data[j];
						if (fd)
							dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr);
						else
							dtdword(&dt, 0);
					}
				}
			}
		}
	}
	
	version (INTERFACE_VIRTUAL) {
		// Put out the overriding interface vtbl[]s.
		// This must be mirrored with ClassDeclaration.baseVtblOffset()
		//printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
		for (size_t i = 0; i < vtblInterfaces.dim; i++)
		{	
			BaseClass b = cast(BaseClass)vtblInterfaces.data[i];
			ClassDeclaration cd;

			for (cd = this.baseClass; cd; cd = cd.baseClass)
			{
				for (int k = 0; k < cd.vtblInterfaces.dim; k++)
				{	
					BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k];

					if (b.base == bs.base)
					{
						//printf("\toverriding vtbl[] for %s\n", b.base.toChars());
						ClassDeclaration id = b.base;
						int j;

						j = 0;
						if (id.vtblOffset())
						{
							// First entry is ClassInfo reference
							//dtxoff(&dt, id.toSymbol(), 0, TYnptr);

							// First entry is struct Interface reference
							dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr);
							j = 1;
						}

						for (; j < id.vtbl.dim; j++)
						{
							assert(j < b.vtbl.dim);
							FuncDeclaration fd = cast(FuncDeclaration)b.vtbl.data[j];
							if (fd)
								dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr);
							else
								dtdword(&dt, 0);
						}
					}
				}
			}
		}
	}


		csym.Sdt = dt;
	version (ELFOBJ_OR_MACHOBJ) { // Burton
		// ClassInfo cannot be const data, because we use the monitor on it
		csym.Sseg = Segment.DATA;
	}
		outdata(csym);
		if (isExport())
			obj_export(csym,0);

		//////////////////////////////////////////////

		// Put out the vtbl[]
		//printf("putting out %s.vtbl[]\n", toChars());
		dt = null;
		size_t i;
		if (0)
			i = 0;
		else
		{	
			dtxoff(&dt, csym, 0, TYnptr);		// first entry is ClassInfo reference
			i = 1;
		}
		for (; i < vtbl.dim; i++)
		{
			FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration();

			//printf("\tvtbl[%d] = %p\n", i, fd);
			if (fd && (fd.fbody || !isAbstract()))
			{   
				Symbol* s = fd.toSymbol();

		version (DMDV2) {
				if (isFuncHidden(fd))
				{	
					/* fd is hidden from the view of this class.
					 * If fd overlaps with any function in the vtbl[], then
					 * issue 'hidden' error.
					 */
					for (int j = 1; j < vtbl.dim; j++)
					{   
						if (j == i)
							continue;
						FuncDeclaration fd2 = (cast(Dsymbol)vtbl.data[j]).isFuncDeclaration();
						if (!fd2.ident.equals(fd.ident))
							continue;
						if (fd.leastAsSpecialized(fd2) || fd2.leastAsSpecialized(fd))
						{
							if (global.params.warnings)
							{
								TypeFunction tf = cast(TypeFunction)fd.type;
								if (tf.ty == Tfunction)
									warning("%s%s is hidden by %s\n", fd.toPrettyChars(), Parameter.argsTypesToChars(tf.parameters, tf.varargs), toChars());
								else
									warning("%s is hidden by %s\n", fd.toPrettyChars(), toChars());
							}
							s = rtlsym[RTLSYM_DHIDDENFUNC];
							break;
						}
					}
				}
		}
				dtxoff(&dt, s, 0, TYnptr);
			}
			else
				dtdword(&dt, 0);
		}

		vtblsym.Sdt = dt;
		vtblsym.Sclass = scclass;
		vtblsym.Sfl = FLdata;
	version (ELFOBJ) {
		vtblsym.Sseg = Segment.CDATA;
	}
	version (MACHOBJ) {
		vtblsym.Sseg = Segment.DATA;
	}
		outdata(vtblsym);
		if (isExport())
			obj_export(vtblsym,0);
	}
	
    void toDebug()
	{
		assert(false);
	}
	
	/******************************************
	 * Get offset of base class's vtbl[] initializer from start of csym.
	 * Returns ~0 if not this csym.
	 */
    uint baseVtblOffset(BaseClass bc)
	{
		uint csymoffset;

		//printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", toChars(), bc);
		csymoffset = CLASSINFO_SIZE;
		csymoffset += vtblInterfaces.dim * (4 * PTRSIZE);

		foreach (b; vtblInterfaces)
		{
			if (b == bc)
				return csymoffset;
			csymoffset += b.base.vtbl.dim * PTRSIZE;
		}

	static if (true) {
		// Put out the overriding interface vtbl[]s.
		// This must be mirrored with ClassDeclaration.baseVtblOffset()
		//printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
		ClassDeclaration cd;
		Array bvtbl;

		for (cd = this.baseClass; cd; cd = cd.baseClass)
		{
			foreach(bs; cd.vtblInterfaces)
			{   
				if (bs.fillVtbl(this, null, 0))
				{
					if (bc == bs)
					{   
						//printf("\tcsymoffset = x%x\n", csymoffset);
						return csymoffset;
					}
					csymoffset += bs.base.vtbl.dim * PTRSIZE;
				}
			}
		}
	}
	version (INTERFACE_VIRTUAL) {
		for (size_t i = 0; i < vtblInterfaces.dim; i++)
		{	
			BaseClass b = cast(BaseClass)vtblInterfaces.data[i];
			ClassDeclaration cd;

			for (cd = this.baseClass; cd; cd = cd.baseClass)
			{
				//printf("\tbase class %s\n", cd.toChars());
				for (int k = 0; k < cd.vtblInterfaces.dim; k++)
				{	
					BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k];

					if (bc == bs)
					{   
						//printf("\tcsymoffset = x%x\n", csymoffset);
						return csymoffset;
					}
					if (b.base == bs.base)
						csymoffset += bs.base.vtbl.dim * PTRSIZE;
				}
			}
		}
	}

		return ~0;
	}
	
	static private __gshared Classsym* scc;

	/*************************************
	 * Create the "ClassInfo" symbol
	 */
    override Symbol* toSymbol()
	{
		if (!csym)
		{
			Symbol* s;

			if (!scc)
				scc = fake_classsym(Id.ClassInfo);

			s = toSymbolX("__Class", SC.SCextern, scc.Stype, "Z");
			s.Sfl = FL.FLextern;
			s.Sflags |= SFL.SFLnodebug;
			csym = s;
			slist_add(s);
		}

		return csym;
	}

	/*************************************
	 * This is accessible via the ClassData, but since it is frequently
	 * needed directly (like for rtti comparisons), make it directly accessible.
	 */
    Symbol* toVtblSymbol()
	{
		if (!vtblsym)
		{
			if (!csym)
				toSymbol();

			TYPE* t = type_alloc(TYM.TYnptr | mTY.mTYconst);
			t.Tnext = tsvoid;
			t.Tnext.Tcount++;
			t.Tmangle = mTYman.mTYman_d;

			Symbol* s = toSymbolX("__vtbl", SC.SCextern, t, "Z");
			s.Sflags |= SFL.SFLnodebug;
			s.Sfl = FL.FLextern;
			vtblsym = s;
			slist_add(s);
		}
		return vtblsym;
	}
	
	// Generate the data for the static initializer.
    void toDt(dt_t **pdt)
	{
		//printf("ClassDeclaration.toDt(this = '%s')\n", toChars());

		// Put in first two members, the vtbl[] and the monitor
		dtxoff(pdt, toVtblSymbol(), 0, TYnptr);
		dtdword(pdt, 0);			// monitor

		// Put in the rest
		toDt2(pdt, this);

		//printf("-ClassDeclaration.toDt(this = '%s')\n", toChars());
	}
	
    void toDt2(dt_t** pdt, ClassDeclaration cd)
	{
		uint offset;

		dt_t* dt;
		uint csymoffset;

	version (LOG) {
		printf("ClassDeclaration.toDt2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
	}
		if (baseClass)
		{
			baseClass.toDt2(pdt, cd);
			offset = baseClass.structsize;
		}
		else
		{
			offset = 8;
		}

		// Note equivalence of this loop to struct's
		for (size_t i = 0; i < fields.dim; i++)
		{
			VarDeclaration v = cast(VarDeclaration)fields[i];
			Initializer init;

			//printf("\t\tv = '%s' v.offset = %2d, offset = %2d\n", v.toChars(), v.offset, offset);
			dt = null;
			init = v.init;
			if (init)
			{   
				//printf("\t\t%s has initializer %s\n", v.toChars(), init.toChars());
				ExpInitializer ei = init.isExpInitializer();
				Type tb = v.type.toBasetype();
				if (ei && tb.ty == Tsarray)
					(cast(TypeSArray)tb).toDtElem(&dt, ei.exp);
				else
					dt = init.toDt();
			}
			else if (v.offset >= offset)
			{   //printf("\t\tdefault initializer\n");
				v.type.toDt(&dt);
			}
			if (dt)
			{
				if (v.offset < offset)
					error("duplicated union initialization for %s", v.toChars());
				else
				{
					if (offset < v.offset)
						dtnzeros(pdt, v.offset - offset);
					dtcat(pdt, dt);
					offset = v.offset + cast(uint)v.type.size();
				}
			}
		}

		// Interface vptr initializations
		toSymbol();						// define csym

		foreach (b; vtblInterfaces)
		{	
///		version (1 || INTERFACE_VIRTUAL) {
			for (ClassDeclaration cd2 = cd; 1; cd2 = cd2.baseClass)
			{
				assert(cd2);
				csymoffset = cd2.baseVtblOffset(b);
				if (csymoffset != ~0)
				{
					if (offset < b.offset)
						dtnzeros(pdt, b.offset - offset);
					dtxoff(pdt, cd2.toSymbol(), csymoffset, TYnptr);
					break;
				}
			}
///		} else {
///			csymoffset = baseVtblOffset(b);
///			assert(csymoffset != ~0);
///			dtxoff(pdt, csym, csymoffset, TYnptr);
///		}
			offset = b.offset + 4;
		}

		if (offset < structsize)
			dtnzeros(pdt, structsize - offset);
	}

    Symbol* vtblsym;

    ///ClassDeclaration isClassDeclaration() { return cast(ClassDeclaration)this; }	/// huh?
    override ClassDeclaration isClassDeclaration() { return this; }
}