diff dmd/ClassDeclaration.d @ 187:b0d41ff5e0df

Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
author Abscissa
date Tue, 07 Jun 2011 23:37:34 -0400
parents cd48cb899aee
children a4c9de8e39b3
line wrap: on
line diff
--- a/dmd/ClassDeclaration.d	Tue Jun 07 21:01:03 2011 -0400
+++ b/dmd/ClassDeclaration.d	Tue Jun 07 23:37:34 2011 -0400
@@ -1,1938 +1,1942 @@
-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 FuncDeclarationFinder
-{
-	bool visit(FuncDeclaration fd2)
-	{
-		//printf("param = %p, fd = %p %s\n", param, fd, fd.toChars());
-		return fd is fd2;
-	}
-
-	FuncDeclaration fd;
-}
-
-class ClassDeclaration : AggregateDeclaration
-{
-    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)
-	{
-		register();
-
-		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 (global.typeinfo) {
-						global.typeinfo.error("%s", msg);
-					}
-
-					global.typeinfo = this;
-				}
-
-				if (id is Id.TypeInfo_Class)
-				{
-					if (global.typeinfoclass)
-						global.typeinfoclass.error("%s", msg);
-					global.typeinfoclass = this;
-				}
-
-				if (id is Id.TypeInfo_Interface)
-				{
-					if (global.typeinfointerface)
-						global.typeinfointerface.error("%s", msg);
-					global.typeinfointerface = this;
-				}
-
-				if (id is Id.TypeInfo_Struct)
-				{
-					if (global.typeinfostruct)
-						global.typeinfostruct.error("%s", msg);
-					global.typeinfostruct = this;
-				}
-
-				if (id is Id.TypeInfo_Typedef)
-				{
-					if (global.typeinfotypedef)
-						global.typeinfotypedef.error("%s", msg);
-					global.typeinfotypedef = this;
-				}
-
-				if (id is Id.TypeInfo_Pointer)
-				{
-					if (global.typeinfopointer)
-						global.typeinfopointer.error("%s", msg);
-					global.typeinfopointer = this;
-				}
-
-				if (id is Id.TypeInfo_Array)
-				{
-					if (global.typeinfoarray)
-						global.typeinfoarray.error("%s", msg);
-					global.typeinfoarray = this;
-				}
-
-				if (id is Id.TypeInfo_StaticArray)
-				{	//if (global.typeinfostaticarray)
-					//global.typeinfostaticarray.error("%s", msg);
-					global.typeinfostaticarray = this;
-				}
-
-				if (id is Id.TypeInfo_AssociativeArray)
-				{
-					if (global.typeinfoassociativearray)
-						global.typeinfoassociativearray.error("%s", msg);
-					global.typeinfoassociativearray = this;
-				}
-
-				if (id is Id.TypeInfo_Enum)
-				{
-					if (global.typeinfoenum)
-						global.typeinfoenum.error("%s", msg);
-					global.typeinfoenum = this;
-				}
-
-				if (id is Id.TypeInfo_Function)
-				{
-					if (global.typeinfofunction)
-						global.typeinfofunction.error("%s", msg);
-					global.typeinfofunction = this;
-				}
-
-				if (id is Id.TypeInfo_Delegate)
-				{
-					if (global.typeinfodelegate)
-						global.typeinfodelegate.error("%s", msg);
-					global.typeinfodelegate = this;
-				}
-
-				if (id is Id.TypeInfo_Tuple)
-				{
-					if (global.typeinfotypelist)
-						global.typeinfotypelist.error("%s", msg);
-					global.typeinfotypelist = this;
-				}
-
-	version (DMDV2) {
-				if (id is Id.TypeInfo_Const)
-				{
-					if (global.typeinfoconst)
-						global.typeinfoconst.error("%s", msg);
-					global.typeinfoconst = this;
-				}
-
-				if (id is Id.TypeInfo_Invariant)
-				{
-					if (global.typeinfoinvariant)
-						global.typeinfoinvariant.error("%s", msg);
-					global.typeinfoinvariant = this;
-				}
-
-				if (id is Id.TypeInfo_Shared)
-				{
-					if (global.typeinfoshared)
-						global.typeinfoshared.error("%s", msg);
-					global.typeinfoshared = this;
-				}
-
-	            if (id == Id.TypeInfo_Wild)
-	            {
-                    if (global.typeinfowild)
-		                global.typeinfowild.error("%s", msg);
-		            global.typeinfowild = this;
-	            }
-	}
-			}
-
-			if (id is Id.Object_)
-			{
-				if (global.object)
-					global.object.error("%s", msg);
-				global.object = this;
-			}
-
-//			if (id is Id.ClassInfo)
-			if (id is Id.TypeInfo_Class)
-			{
-				if (global.classinfo)
-					global.classinfo.error("%s", msg);
-				global.classinfo = this;
-			}
-
-			if (id is Id.ModuleInfo)
-			{
-				if (global.moduleinfo)
-					global.moduleinfo.error("%s", msg);
-				global.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 (sizeok == 1 || !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;
-		}
-	    uint dprogress_save = global.dprogress;
-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 (!global.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 = global.tvoidptr;
-						}
-					}
-					else
-						assert(0);
-					if (t.ty == TY.Tstruct)	// ref to struct
-						t = global.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);
-			
-			global.dprogress = dprogress_save;
-
-			//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;
-		global.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;
-		}
-
-		FuncDeclarationFinder 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))
-					return false;
-			}
-			return true;
-		}
-		else
-		{
-			FuncDeclaration fdstart = s.isFuncDeclaration();
-			//printf("%s fdstart = %p\n", s.kind(), fdstart);
-			return !overloadApply(fdstart, 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 global.object     ||
-			this is global.classinfo  ||
-			this is global.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 (global.classinfo)
-		{
-			if (global.classinfo.structsize != CLASSINFO_SIZE)
-				error("D compiler and phobos' object.d are mismatched");
-
-			dtxoff(&dt, global.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;
-	}
-
-	/*************************************
-	 * Create the "ClassInfo" symbol
-	 */
-    override Symbol* toSymbol()
-	{
-		if (!csym)
-		{
-			Symbol* s;
-
-			s = toSymbolX("__Class", SC.SCextern, global.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; }
-}
+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 dmd.DDMDExtensions;
+
+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 FuncDeclarationFinder
+{
+	bool visit(FuncDeclaration fd2)
+	{
+		//printf("param = %p, fd = %p %s\n", param, fd, fd.toChars());
+		return fd is fd2;
+	}
+
+	FuncDeclaration fd;
+}
+
+class ClassDeclaration : AggregateDeclaration
+{
+	mixin insertMemberExtension!(typeof(this));
+
+    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)
+	{
+		register();
+
+		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 (global.typeinfo) {
+						global.typeinfo.error("%s", msg);
+					}
+
+					global.typeinfo = this;
+				}
+
+				if (id is Id.TypeInfo_Class)
+				{
+					if (global.typeinfoclass)
+						global.typeinfoclass.error("%s", msg);
+					global.typeinfoclass = this;
+				}
+
+				if (id is Id.TypeInfo_Interface)
+				{
+					if (global.typeinfointerface)
+						global.typeinfointerface.error("%s", msg);
+					global.typeinfointerface = this;
+				}
+
+				if (id is Id.TypeInfo_Struct)
+				{
+					if (global.typeinfostruct)
+						global.typeinfostruct.error("%s", msg);
+					global.typeinfostruct = this;
+				}
+
+				if (id is Id.TypeInfo_Typedef)
+				{
+					if (global.typeinfotypedef)
+						global.typeinfotypedef.error("%s", msg);
+					global.typeinfotypedef = this;
+				}
+
+				if (id is Id.TypeInfo_Pointer)
+				{
+					if (global.typeinfopointer)
+						global.typeinfopointer.error("%s", msg);
+					global.typeinfopointer = this;
+				}
+
+				if (id is Id.TypeInfo_Array)
+				{
+					if (global.typeinfoarray)
+						global.typeinfoarray.error("%s", msg);
+					global.typeinfoarray = this;
+				}
+
+				if (id is Id.TypeInfo_StaticArray)
+				{	//if (global.typeinfostaticarray)
+					//global.typeinfostaticarray.error("%s", msg);
+					global.typeinfostaticarray = this;
+				}
+
+				if (id is Id.TypeInfo_AssociativeArray)
+				{
+					if (global.typeinfoassociativearray)
+						global.typeinfoassociativearray.error("%s", msg);
+					global.typeinfoassociativearray = this;
+				}
+
+				if (id is Id.TypeInfo_Enum)
+				{
+					if (global.typeinfoenum)
+						global.typeinfoenum.error("%s", msg);
+					global.typeinfoenum = this;
+				}
+
+				if (id is Id.TypeInfo_Function)
+				{
+					if (global.typeinfofunction)
+						global.typeinfofunction.error("%s", msg);
+					global.typeinfofunction = this;
+				}
+
+				if (id is Id.TypeInfo_Delegate)
+				{
+					if (global.typeinfodelegate)
+						global.typeinfodelegate.error("%s", msg);
+					global.typeinfodelegate = this;
+				}
+
+				if (id is Id.TypeInfo_Tuple)
+				{
+					if (global.typeinfotypelist)
+						global.typeinfotypelist.error("%s", msg);
+					global.typeinfotypelist = this;
+				}
+
+	version (DMDV2) {
+				if (id is Id.TypeInfo_Const)
+				{
+					if (global.typeinfoconst)
+						global.typeinfoconst.error("%s", msg);
+					global.typeinfoconst = this;
+				}
+
+				if (id is Id.TypeInfo_Invariant)
+				{
+					if (global.typeinfoinvariant)
+						global.typeinfoinvariant.error("%s", msg);
+					global.typeinfoinvariant = this;
+				}
+
+				if (id is Id.TypeInfo_Shared)
+				{
+					if (global.typeinfoshared)
+						global.typeinfoshared.error("%s", msg);
+					global.typeinfoshared = this;
+				}
+
+	            if (id == Id.TypeInfo_Wild)
+	            {
+                    if (global.typeinfowild)
+		                global.typeinfowild.error("%s", msg);
+		            global.typeinfowild = this;
+	            }
+	}
+			}
+
+			if (id is Id.Object_)
+			{
+				if (global.object)
+					global.object.error("%s", msg);
+				global.object = this;
+			}
+
+//			if (id is Id.ClassInfo)
+			if (id is Id.TypeInfo_Class)
+			{
+				if (global.classinfo)
+					global.classinfo.error("%s", msg);
+				global.classinfo = this;
+			}
+
+			if (id is Id.ModuleInfo)
+			{
+				if (global.moduleinfo)
+					global.moduleinfo.error("%s", msg);
+				global.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 (sizeok == 1 || !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;
+		}
+	    uint dprogress_save = global.dprogress;
+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 (!global.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 = global.tvoidptr;
+						}
+					}
+					else
+						assert(0);
+					if (t.ty == TY.Tstruct)	// ref to struct
+						t = global.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);
+			
+			global.dprogress = dprogress_save;
+
+			//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;
+		global.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;
+		}
+
+		FuncDeclarationFinder 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))
+					return false;
+			}
+			return true;
+		}
+		else
+		{
+			FuncDeclaration fdstart = s.isFuncDeclaration();
+			//printf("%s fdstart = %p\n", s.kind(), fdstart);
+			return !overloadApply(fdstart, 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 global.object     ||
+			this is global.classinfo  ||
+			this is global.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 (global.classinfo)
+		{
+			if (global.classinfo.structsize != CLASSINFO_SIZE)
+				error("D compiler and phobos' object.d are mismatched");
+
+			dtxoff(&dt, global.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;
+	}
+
+	/*************************************
+	 * Create the "ClassInfo" symbol
+	 */
+    override Symbol* toSymbol()
+	{
+		if (!csym)
+		{
+			Symbol* s;
+
+			s = toSymbolX("__Class", SC.SCextern, global.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; }
+}