diff dmd/StructDeclaration.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 427f8aa74d28
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/StructDeclaration.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,851 @@
+module dmd.StructDeclaration;
+
+import dmd.AggregateDeclaration;
+import dmd.FuncDeclaration;
+import dmd.DeclarationExp;
+import dmd.VoidInitializer;
+import dmd.Initializer;
+import dmd.ExpInitializer;
+import dmd.TOK;
+import dmd.Statement;
+import dmd.VarExp;
+import dmd.CompoundStatement;
+import dmd.AssignExp;
+import dmd.DotVarExp;
+import dmd.AddrExp;
+import dmd.CastExp;
+import dmd.PostBlitDeclaration;
+import dmd.Lexer;
+import dmd.ExpStatement;
+import dmd.DotIdExp;
+import dmd.TypeSArray;
+import dmd.ThisExp;
+import dmd.ThisDeclaration;
+import dmd.TypeFunction;
+import dmd.Argument;
+import dmd.Id;
+import dmd.TY;
+import dmd.LINK;
+import dmd.Type;
+import dmd.DsymbolTable;
+import dmd.ArrayTypes;
+import dmd.Loc;
+import dmd.STC;
+import dmd.Identifier;
+import dmd.TemplateInstance;
+import dmd.Dsymbol;
+import dmd.Scope;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.PROT;
+import dmd.TypeStruct;
+import dmd.expression.Util;
+import dmd.Expression;
+import dmd.IdentifierExp;
+import dmd.PtrExp;
+import dmd.CallExp;
+import dmd.ReturnStatement;
+import dmd.ScopeDsymbol;
+import dmd.Module;
+import dmd.VarDeclaration;
+import dmd.InvariantDeclaration;
+import dmd.NewDeclaration;
+import dmd.DeleteDeclaration;
+import dmd.Global;
+
+import dmd.backend.dt_t;
+import dmd.backend.Util;
+import dmd.backend.SC;
+import dmd.backend.DT;
+import dmd.backend.FL;
+import dmd.backend.glue;
+
+class StructDeclaration : AggregateDeclaration
+{
+    bool zeroInit;		// true if initialize with 0 fill
+	
+version (DMDV2) {
+    int hasIdentityAssign;	// !=0 if has identity opAssign
+    FuncDeclaration cpctor;	// generated copy-constructor, if any
+
+    FuncDeclarations postblits;	// Array of postblit functions
+    FuncDeclaration postblit;	// aggregate postblit
+}
+
+    this(Loc loc, Identifier id)
+	{
+		super(loc, id);
+
+		// For forward references
+		type = new TypeStruct(this);
+		
+		postblits = new FuncDeclarations(); ///
+	}
+	
+    Dsymbol syntaxCopy(Dsymbol s)
+	{
+		assert(false);
+	}
+	
+    void semantic(Scope sc)
+	{
+		int i;
+		Scope sc2;
+
+		//printf("+StructDeclaration.semantic(this=%p, '%s')\n", this, toChars());
+
+		//static int count; if (++count == 20) *(char*)0=0;
+
+		assert(type);
+		if (!members)			// if forward reference
+		return;
+
+		if (symtab)
+		{   if (!scope_)
+				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;
+		}
+
+		parent = sc.parent;
+		type = type.semantic(loc, sc);
+version (STRUCTTHISREF) {
+		handle = type;
+} else {
+		handle = type.pointerTo();
+}
+		structalign = sc.structalign;
+		protection = sc.protection;
+		storage_class |= sc.stc;
+		if (sc.stc & STC.STCdeprecated)
+		isdeprecated = 1;
+		assert(!isAnonymous());
+		if (sc.stc & STC.STCabstract)
+		error("structs, unions cannot be abstract");
+version (DMDV2) {
+		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();
+}
+
+		if (sizeok == 0)		// if not already done the addMember step
+		{
+		int hasfunctions = 0;
+		for (i = 0; i < members.dim; i++)
+		{
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			//printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars());
+			s.addMember(sc, this, 1);
+			if (s.isFuncDeclaration())
+			hasfunctions = 1;
+		}
+
+		// If nested struct, add in hidden 'this' pointer to outer scope
+		if (hasfunctions && !(storage_class & STC.STCstatic))
+			{   Dsymbol s = toParent2();
+				if (s)
+				{
+					AggregateDeclaration ad = s.isAggregateDeclaration();
+					FuncDeclaration fd = s.isFuncDeclaration();
+
+			TemplateInstance ti;
+					if (ad && (ti = ad.parent.isTemplateInstance()) !is null && ti.isnested || fd)
+					{   isnested = true;
+						Type t;
+						if (ad)
+							t = ad.handle;
+						else if (fd)
+						{   
+							AggregateDeclaration add = fd.isMember2();
+							if (add)
+								t = add.handle;
+							else
+								t = Type.tvoidptr;
+						}
+						else
+							assert(0);
+				if (t.ty == TY.Tstruct)
+				t = Type.tvoidptr;	// t should not be a ref type
+						assert(!vthis);
+						vthis = new ThisDeclaration(loc, t);
+				//vthis.storage_class |= STC.STCref;
+						members.push(cast(void*)vthis);
+					}
+				}
+			}
+		}
+
+		sizeok = 0;
+		sc2 = sc.push(this);
+		sc2.stc &= storage_class & STC.STC_TYPECTOR;
+		sc2.parent = this;
+		if (isUnionDeclaration())
+		sc2.inunion = 1;
+		sc2.protection = PROT.PROTpublic;
+		sc2.explicitProtection = 0;
+
+		int members_dim = members.dim;
+		for (i = 0; i < members_dim; i++)
+		{
+		Dsymbol s = cast(Dsymbol)members.data[i];
+		s.semantic(sc2);
+		if (isUnionDeclaration())
+			sc2.offset = 0;
+static if (false) {
+		if (sizeok == 2)
+		{   //printf("forward reference\n");
+			break;
+		}
+}
+		Type t;
+		if (s.isDeclaration() &&
+			(t = s.isDeclaration().type) !is null &&
+			t.toBasetype().ty == TY.Tstruct)
+		{   StructDeclaration sd = cast(StructDeclaration)t.toDsymbol(sc);
+			if (sd.isnested)
+			error("inner struct %s cannot be a field", sd.toChars());
+		}
+		}
+
+		/* The TypeInfo_Struct is expecting an opEquals and opCmp with
+		 * a parameter that is a pointer to the struct. But if there
+		 * isn't one, but is an opEquals or opCmp with a value, write
+		 * another that is a shell around the value:
+		 *	int opCmp(struct *p) { return opCmp(*p); }
+		 */
+
+		TypeFunction tfeqptr;
+		{
+		Arguments arguments = new Arguments;
+		Argument arg = new Argument(STC.STCin, handle, Id.p, null);
+
+		arguments.push(cast(void*)arg);
+		tfeqptr = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd);
+		tfeqptr = cast(TypeFunction)tfeqptr.semantic(Loc(0), sc);
+		}
+
+		TypeFunction tfeq;
+		{
+		Arguments arguments = new Arguments;
+		Argument arg = new Argument(STC.STCin, type, null, null);
+
+		arguments.push(cast(void*)arg);
+		tfeq = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd);
+		tfeq = cast(TypeFunction)tfeq.semantic(Loc(0), sc);
+		}
+
+		Identifier id = Id.eq;
+		for (int j = 0; j < 2; j++)
+		{
+			Dsymbol s = search_function(this, id);
+			FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
+			if (fdx)
+			{   FuncDeclaration fd = fdx.overloadExactMatch(tfeqptr);
+				if (!fd)
+				{	fd = fdx.overloadExactMatch(tfeq);
+				if (fd)
+				{   // Create the thunk, fdptr
+					FuncDeclaration fdptr = new FuncDeclaration(loc, loc, fdx.ident, STC.STCundefined, tfeqptr);
+					Expression e = new IdentifierExp(loc, Id.p);
+					e = new PtrExp(loc, e);
+					Expressions args = new Expressions();
+					args.push(cast(void*)e);
+					e = new IdentifierExp(loc, id);
+					e = new CallExp(loc, e, args);
+					fdptr.fbody = new ReturnStatement(loc, e);
+					ScopeDsymbol ss = fdx.parent.isScopeDsymbol();
+					assert(ss);
+					ss.members.push(cast(void*)fdptr);
+					fdptr.addMember(sc, ss, 1);
+					fdptr.semantic(sc2);
+				}
+				}
+			}
+
+			id = Id.cmp;
+		}
+version (DMDV2) {
+		dtor = buildDtor(sc2);
+		postblit = buildPostBlit(sc2);
+		cpctor = buildCpCtor(sc2);
+		buildOpAssign(sc2);
+}
+
+		sc2.pop();
+
+		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;
+
+		scope_ = scx ? scx : new Scope(sc);
+		scope_.setNoFree();
+		scope_.module_.addDeferredSemantic(this);
+		//printf("\tdeferring %s\n", toChars());
+		return;
+		}
+
+		// 0 sized struct's are set to 1 byte
+		if (structsize == 0)
+		{
+		structsize = 1;
+		alignsize = 1;
+		}
+
+		// Round struct size up to next alignsize boundary.
+		// This will ensure that arrays of structs will get their internals
+		// aligned properly.
+		structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+
+		sizeok = 1;
+		Module.dprogress++;
+
+		//printf("-StructDeclaration.semantic(this=%p, '%s')\n", this, toChars());
+
+		// Determine if struct is all zeros or not
+		zeroInit = true;
+		for (i = 0; i < fields.dim; i++)
+		{
+		Dsymbol s = cast(Dsymbol)fields.data[i];
+		VarDeclaration vd = s.isVarDeclaration();
+		if (vd && !vd.isDataseg())
+		{
+			if (vd.init)
+			{
+			// Should examine init to see if it is really all 0's
+			zeroInit = false;
+			break;
+			}
+			else
+			{
+			if (!vd.type.isZeroInit(loc))
+			{
+				zeroInit = false;
+				break;
+			}
+			}
+		}
+		}
+
+		/* Look for special member functions.
+		 */
+version (DMDV2) {
+		ctor = search(Loc(0), Id.ctor, 0);
+}
+		inv =    cast(InvariantDeclaration)search(Loc(0), Id.classInvariant, 0);
+		aggNew =       cast(NewDeclaration)search(Loc(0), Id.classNew,       0);
+		aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete,    0);
+
+		if (sc.func)
+		{
+		semantic2(sc);
+		semantic3(sc);
+		}
+	}
+	
+    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		assert(false);
+	}
+	
+    string mangle()
+	{
+		//printf("StructDeclaration.mangle() '%s'\n", toChars());
+		return Dsymbol.mangle();
+	}
+	
+    string kind()
+	{
+		assert(false);
+	}
+	
+	/*******************************************
+	 * We need an opAssign for the struct if
+	 * it has a destructor or a postblit.
+	 * We need to generate one if a user-specified one does not exist.
+	 */
+    bool needOpAssign()
+	{
+static if (false) {
+		printf("StructDeclaration.needOpAssign() %s\n", toChars());
+}
+		if (hasIdentityAssign)
+			goto Ldontneed;
+
+		if (dtor || postblit)
+			goto Lneed;
+
+		/* If any of the fields need an opAssign, then we
+		 * need it too.
+		 */
+		for (size_t i = 0; i < fields.dim; i++)
+		{
+			Dsymbol s = cast(Dsymbol)fields.data[i];
+			VarDeclaration v = s.isVarDeclaration();
+			assert(v && v.storage_class & STC.STCfield);
+			if (v.storage_class & STC.STCref)
+				continue;
+			Type tv = v.type.toBasetype();
+			while (tv.ty == TY.Tsarray)
+			{   TypeSArray ta = cast(TypeSArray)tv;
+				tv = tv.nextOf().toBasetype();
+			}
+			if (tv.ty == TY.Tstruct)
+			{   TypeStruct ts = cast(TypeStruct)tv;
+				StructDeclaration sd = ts.sym;
+				if (sd.needOpAssign())
+					goto Lneed;
+			}
+		}
+	Ldontneed:
+static if (false) {
+		printf("\tdontneed\n");
+}
+		return false;
+
+	Lneed:
+static if (false) {
+		printf("\tneed\n");
+}
+		return true;
+	}
+	
+	/******************************************
+	 * Build opAssign for struct.
+	 *	S* opAssign(S s) { ... }
+	 */
+    FuncDeclaration buildOpAssign(Scope sc)
+	{
+		if (!needOpAssign())
+			return null;
+
+		//printf("StructDeclaration.buildOpAssign() %s\n", toChars());
+
+		FuncDeclaration fop = null;
+
+		Argument param = new Argument(STC.STCnodtor, type, Id.p, null);
+		Arguments fparams = new Arguments;
+		fparams.push(cast(void*)param);
+		Type ftype = new TypeFunction(fparams, handle, false, LINK.LINKd);
+version (STRUCTTHISREF) {
+		(cast(TypeFunction)ftype).isref = 1;
+}
+
+		fop = new FuncDeclaration(Loc(0), Loc(0), Id.assign, STC.STCundefined, ftype);
+
+		Expression e = null;
+		if (postblit)
+		{	/* Swap:
+			 *    tmp = *this; *this = s; tmp.dtor();
+			 */
+		//printf("\tswap copy\n");
+		Identifier idtmp = Lexer.uniqueId("__tmp");
+		VarDeclaration tmp;
+		AssignExp ec = null;
+		if (dtor)
+		{
+			tmp = new VarDeclaration(Loc(0), type, idtmp, new VoidInitializer(Loc(0)));
+			tmp.noauto = true;
+			e = new DeclarationExp(Loc(0), tmp);
+
+			Expression e2;
+version (STRUCTTHISREF) {
+			e2 = new ThisExp(Loc(0));
+} else {
+			e2 = new PtrExp(Loc(0), new ThisExp(Loc(0)));
+}
+			ec = new AssignExp(Loc(0), new VarExp(Loc(0), tmp), e2);
+			ec.op = TOK.TOKblit;
+			e = Expression.combine(e, ec);
+		}
+		Expression e2;
+version (STRUCTTHISREF) {
+			e2 = new ThisExp(Loc(0));
+} else {
+			e2 = new PtrExp(Loc(0), new ThisExp(Loc(0)));
+}
+	
+		ec = new AssignExp(Loc(0), e2, new IdentifierExp(Loc(0), Id.p));
+		ec.op = TOK.TOKblit;
+		e = Expression.combine(e, ec);
+		if (dtor)
+		{
+			/* Instead of running the destructor on s, run it
+			 * on tmp. This avoids needing to copy tmp back in to s.
+			 */
+			Expression ecc = new DotVarExp(Loc(0), new VarExp(Loc(0), tmp), dtor, 0);
+			ecc = new CallExp(Loc(0), ecc);
+			e = Expression.combine(e, ecc);
+		}
+		}
+		else
+		{	/* Do memberwise copy
+			 */
+		//printf("\tmemberwise copy\n");
+		for (size_t i = 0; i < fields.dim; i++)
+		{
+			Dsymbol s = cast(Dsymbol)fields.data[i];
+			VarDeclaration v = s.isVarDeclaration();
+			assert(v && v.storage_class & STC.STCfield);
+			// this.v = s.v;
+			AssignExp ec = new AssignExp(Loc(0), new DotVarExp(Loc(0), new ThisExp(Loc(0)), v, 0), new DotVarExp(Loc(0), new IdentifierExp(Loc(0), Id.p), v, 0));
+			ec.op = TOK.TOKblit;
+			e = Expression.combine(e, ec);
+		}
+		}
+		Statement s1 = new ExpStatement(Loc(0), e);
+
+		/* Add:
+		 *   return this;
+		 */
+		e = new ThisExp(Loc(0));
+		Statement s2 = new ReturnStatement(Loc(0), e);
+
+		fop.fbody = new CompoundStatement(Loc(0), s1, s2);
+
+		members.push(cast(void*)fop);
+		fop.addMember(sc, this, 1);
+
+		sc = sc.push();
+		sc.stc = STC.STCundefined;
+		sc.linkage = LINK.LINKd;
+
+		fop.semantic(sc);
+
+		sc.pop();
+
+		//printf("-StructDeclaration.buildOpAssign() %s\n", toChars());
+
+		return fop;
+	}
+	
+	/*****************************************
+	 * Create inclusive postblit for struct by aggregating
+	 * all the postblits in postblits[] with the postblits for
+	 * all the members.
+	 * Note the close similarity with AggregateDeclaration.buildDtor(),
+	 * and the ordering changes (runs forward instead of backwards).
+	 */
+
+version (DMDV2) {
+    FuncDeclaration buildPostBlit(Scope sc)
+	{
+		//printf("StructDeclaration.buildPostBlit() %s\n", toChars());
+		Expression e = null;
+
+		for (size_t i = 0; i < fields.dim; i++)
+		{
+		Dsymbol s = cast(Dsymbol)fields.data[i];
+		VarDeclaration v = s.isVarDeclaration();
+		assert(v && v.storage_class & STC.STCfield);
+		if (v.storage_class & STC.STCref)
+			continue;
+		Type tv = v.type.toBasetype();
+		size_t dim = 1;
+		while (tv.ty == TY.Tsarray)
+		{   TypeSArray ta = cast(TypeSArray)tv;
+			dim *= (cast(TypeSArray)tv).dim.toInteger();
+			tv = tv.nextOf().toBasetype();
+		}
+		if (tv.ty == TY.Tstruct)
+		{   TypeStruct ts = cast(TypeStruct)tv;
+			StructDeclaration sd = ts.sym;
+			if (sd.postblit)
+			{	Expression ex;
+
+			// this.v
+			ex = new ThisExp(Loc(0));
+			ex = new DotVarExp(Loc(0), ex, v, 0);
+
+			if (dim == 1)
+			{   // this.v.postblit()
+				ex = new DotVarExp(Loc(0), ex, sd.postblit, 0);
+				ex = new CallExp(Loc(0), ex);
+			}
+			else
+			{
+				// Typeinfo.postblit(cast(void*)&this.v);
+				Expression ea = new AddrExp(Loc(0), ex);
+				ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo());
+
+				Expression et = v.type.getTypeInfo(sc);
+				et = new DotIdExp(Loc(0), et, Id.postblit);
+
+				ex = new CallExp(Loc(0), et, ea);
+			}
+			e = Expression.combine(e, ex);	// combine in forward order
+			}
+		}
+		}
+
+		/* Build our own "postblit" which executes e
+		 */
+		if (e)
+		{	//printf("Building __fieldPostBlit()\n");
+		PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldPostBlit"));
+		dd.fbody = new ExpStatement(Loc(0), e);
+		postblits.shift(cast(void*)dd);
+		members.push(cast(void*)dd);
+		dd.semantic(sc);
+		}
+
+		switch (postblits.dim)
+		{
+		case 0:
+			return null;
+
+		case 1:
+			return cast(FuncDeclaration)postblits.data[0];
+
+		default:
+			e = null;
+			for (size_t i = 0; i < postblits.dim; i++)
+			{	FuncDeclaration fd = cast(FuncDeclaration)postblits.data[i];
+			Expression ex = new ThisExp(Loc(0));
+			ex = new DotVarExp(Loc(0), ex, fd, 0);
+			ex = new CallExp(Loc(0), ex);
+			e = Expression.combine(e, ex);
+			}
+			PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrPostBlit"));
+			dd.fbody = new ExpStatement(Loc(0), e);
+			members.push(cast(void*)dd);
+			dd.semantic(sc);
+			return dd;
+		}
+	}
+}
+
+	/*******************************************
+	 * Build copy constructor for struct.
+	 * Copy constructors are compiler generated only, and are only
+	 * callable from the compiler. They are not user accessible.
+	 * A copy constructor is:
+	 *    void cpctpr(ref S s)
+	 *    {
+	 *	*this = s;
+	 *	this.postBlit();
+	 *    }
+	 * This is done so:
+	 *	- postBlit() never sees uninitialized data
+	 *	- memcpy can be much more efficient than memberwise copy
+	 *	- no fields are overlooked
+	 */
+    FuncDeclaration buildCpCtor(Scope sc)
+	{
+		//printf("StructDeclaration.buildCpCtor() %s\n", toChars());
+		FuncDeclaration fcp = null;
+
+		/* Copy constructor is only necessary if there is a postblit function,
+		 * otherwise the code generator will just do a bit copy.
+		 */
+		if (postblit)
+		{
+		//printf("generating cpctor\n");
+
+		Argument param = new Argument(STC.STCref, type, Id.p, null);
+		Arguments fparams = new Arguments;
+		fparams.push(cast(void*)param);
+		Type ftype = new TypeFunction(fparams, Type.tvoid, false, LINK.LINKd);
+
+		fcp = new FuncDeclaration(Loc(0), Loc(0), Id.cpctor, STC.STCundefined, ftype);
+
+		// Build *this = p;
+		Expression e = new ThisExp(Loc(0));
+version (STRUCTTHISREF) {
+} else {
+		e = new PtrExp(Loc(0), e);
+}
+		AssignExp ea = new AssignExp(Loc(0), e, new IdentifierExp(Loc(0), Id.p));
+		ea.op = TOK.TOKblit;
+		Statement s = new ExpStatement(Loc(0), ea);
+
+		// Build postBlit();
+		e = new VarExp(Loc(0), postblit, 0);
+		e = new CallExp(Loc(0), e);
+
+		s = new CompoundStatement(Loc(0), s, new ExpStatement(Loc(0), e));
+		fcp.fbody = s;
+
+		members.push(cast(void*)fcp);
+
+		sc = sc.push();
+		sc.stc = STC.STCundefined;
+		sc.linkage = LINK.LINKd;
+
+		fcp.semantic(sc);
+
+		sc.pop();
+		}
+
+		return fcp;
+	}
+	
+    void toDocBuffer(OutBuffer buf)
+	{
+		assert(false);
+	}
+	
+    PROT getAccess(Dsymbol smember)	// determine access to smember
+	{
+		assert(false);
+	}
+
+    void toObjFile(int multiobj)			// compile to .obj file
+	{
+		//printf("StructDeclaration.toObjFile('%s')\n", toChars());
+
+		if (multiobj)
+		{	
+			obj_append(this);
+			return;
+		}
+
+		// Anonymous structs/unions only exist as part of others,
+		// do not output forward referenced structs's
+		if (!isAnonymous() && members)
+		{
+			if (global.params.symdebug) {
+				toDebug();
+			}
+
+			type.getTypeInfo(null);	// generate TypeInfo
+
+			if (true)
+			{
+				// Generate static initializer
+				toInitializer();
+
+static if (false) {
+				sinit.Sclass = SC.SCcomdat;
+} else {
+				if (inTemplateInstance())
+				{
+					sinit.Sclass = SC.SCcomdat;
+				}
+				else
+				{
+					sinit.Sclass = SC.SCglobal;
+				}
+}
+				sinit.Sfl = FL.FLdata;
+
+				toDt(&sinit.Sdt);
+
+version (OMFOBJ) {
+				/* For OMF, common blocks aren't pulled in from the library.
+				 */
+				/* ELF comdef's generate multiple
+				 * definition errors for them from the gnu linker.
+				 * Need to figure out how to generate proper comdef's for ELF.
+				 */
+				// See if we can convert a comdat to a comdef,
+				// which saves on exe file space.
+				if (sinit.Sclass == SCcomdat &&
+					sinit.Sdt &&
+					sinit.Sdt.dt == DT.DT_azeros &&
+					sinit.Sdt.DTnext == null &&
+					!global.params.multiobj)
+				{
+					sinit.Sclass = SC.SCglobal;
+					sinit.Sdt.dt = DT.DT_common;
+				}
+}
+
+version (ELFOBJ) {
+				sinit.Sseg = Segment.CDATA;
+}
+version (MACHOBJ) {
+				sinit.Sseg = Segment.DATA;
+}
+				outdata(sinit);
+			}
+
+			// Put out the members
+			for (uint i = 0; i < members.dim; i++)
+			{
+				Dsymbol member = cast(Dsymbol)members.data[i];
+				member.toObjFile(0);
+			}
+		}
+	}
+	
+    void toDt(dt_t** pdt)
+	{
+		uint offset;
+		uint i;
+		dt_t* dt;
+
+		//printf("StructDeclaration.toDt(), this='%s'\n", toChars());
+		offset = 0;
+
+		// Note equivalence of this loop to class's
+		for (i = 0; i < fields.dim; i++)
+		{
+			VarDeclaration v = cast(VarDeclaration)fields.data[i];
+			//printf("\tfield '%s' voffset %d, offset = %d\n", v.toChars(), v.offset, offset);
+			dt = null;
+			int sz;
+
+			if (v.storage_class & STC.STCref)
+			{
+				sz = PTRSIZE;
+				if (v.offset >= offset)
+					dtnzeros(&dt, sz);
+			}
+			else
+			{
+				sz = cast(uint)v.type.size();
+				Initializer init = v.init;
+				if (init)
+				{   
+					//printf("\t\thas initializer %s\n", init.toChars());
+					ExpInitializer ei = init.isExpInitializer();
+					Type tb = v.type.toBasetype();
+					if (ei && tb.ty == TY.Tsarray)
+						(cast(TypeSArray)tb).toDtElem(&dt, ei.exp);
+					else
+						dt = init.toDt();
+				}
+				else if (v.offset >= offset)
+					v.type.toDt(&dt);
+			}
+			if (dt)
+			{
+				if (v.offset < offset)
+					error("overlapping initialization for struct %s.%s", toChars(), v.toChars());
+				else
+				{
+					if (offset < v.offset)
+						dtnzeros(pdt, v.offset - offset);
+					dtcat(pdt, dt);
+					offset = v.offset + sz;
+				}
+			}
+		}
+
+		if (offset < structsize)
+			dtnzeros(pdt, structsize - offset);
+
+		dt_optimize(*pdt);
+	}
+	
+    void toDebug()			// to symbolic debug info
+	{
+		assert(false);
+	}
+
+    StructDeclaration isStructDeclaration() { return this; }
+}
\ No newline at end of file