diff dmd/VarDeclaration.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 832f71e6f96c 5c9b78899f5d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/VarDeclaration.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,1188 @@
+module dmd.VarDeclaration;
+
+import dmd.Declaration;
+import dmd.SliceExp;
+import dmd.ClassDeclaration;
+import dmd.DeleteExp;
+import dmd.SymOffExp;
+import dmd.DotIdExp;
+import dmd.PtrExp;
+import dmd.CallExp;
+import dmd.DotVarExp;
+import dmd.CommaExp;
+import dmd.CastExp;
+import dmd.WANT;
+import dmd.StructDeclaration;
+import dmd.DsymbolExp;
+import dmd.TypeSArray;
+import dmd.IntegerExp;
+import dmd.VarExp;
+import dmd.AssignExp;
+import dmd.TypeTypedef;
+import dmd.ArrayInitializer;
+import dmd.StructInitializer;
+import dmd.NewExp;
+import dmd.TupleDeclaration;
+import dmd.AggregateDeclaration;
+import dmd.InterfaceDeclaration;
+import dmd.TemplateInstance;
+import dmd.Id;
+import dmd.Initializer;
+import dmd.TypeStruct;
+import dmd.TypeTuple;
+import dmd.Argument;
+import dmd.ExpInitializer;
+import dmd.ArrayTypes;
+import dmd.Dsymbol;
+import dmd.Expression;
+import dmd.Loc;
+import dmd.STC;
+import dmd.TOK;
+import dmd.TupleExp;
+import dmd.Global;
+import dmd.FuncDeclaration;
+import dmd.Type;
+import dmd.TY;
+import dmd.LINK;
+import dmd.Scope;
+import dmd.Identifier;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.PROT;
+
+import dmd.backend.Symbol;
+import dmd.backend.TYM;
+import dmd.backend.FL;
+import dmd.backend.DT;
+import dmd.backend.mTY;
+import dmd.backend.SC;
+import dmd.backend.mTYman;
+import dmd.backend.TYPE;
+import dmd.backend.Util;
+import dmd.backend.LIST;
+
+import std.stdio : writef;
+import std.string : toStringz;
+
+class VarDeclaration : Declaration
+{
+    Initializer init;
+    uint offset;
+    bool noauto;			// no auto semantics
+version (DMDV2) {
+    FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+} else {
+    int nestedref;		// referenced by a lexically nested function
+}
+    int ctorinit;		// it has been initialized in a ctor
+    int onstack;		// 1: it has been allocated on the stack
+				// 2: on stack, run destructor anyway
+    int canassign;		// it can be assigned to
+    Dsymbol aliassym;		// if redone as alias to another symbol
+    Expression value;		// when interpreting, this is the value
+				// (null if value not determinable)
+version (DMDV2) {
+    VarDeclaration rundtor;	// if !null, rundtor is tested at runtime to see
+				// if the destructor should be run. Used to prevent
+				// dtor calls on postblitted vars
+}
+
+    this(Loc loc, Type type, Identifier id, Initializer init)
+	{
+		super(id);
+		
+debug {
+		if (!type && !init)
+		{
+			writef("VarDeclaration('%s')\n", id.toChars());
+			//*(char*)0=0;
+		}
+}
+		assert(type || init);
+		this.type = type;
+		this.init = init;
+		this.loc = loc;
+		
+		nestedrefs = new FuncDeclarations();
+	}
+
+    Dsymbol syntaxCopy(Dsymbol s)
+	{
+		//printf("VarDeclaration.syntaxCopy(%s)\n", toChars());
+
+		VarDeclaration sv;
+		if (s)
+		{	
+			sv = cast(VarDeclaration)s;
+		}
+		else
+		{
+			Initializer init = null;
+			if (this.init)
+			{   
+				init = this.init.syntaxCopy();
+				//init.isExpInitializer().exp.print();
+				//init.isExpInitializer().exp.dump(0);
+			}
+
+			sv = new VarDeclaration(loc, type ? type.syntaxCopy() : null, ident, init);
+			sv.storage_class = storage_class;
+		}
+
+	version (_DH) {
+		// Syntax copy for header file
+		if (!htype)      // Don't overwrite original
+		{
+			if (type)    // Make copy for both old and new instances
+			{   htype = type.syntaxCopy();
+				sv.htype = type.syntaxCopy();
+			}
+		}
+		else            // Make copy of original for new instance
+			sv.htype = htype.syntaxCopy();
+		if (!hinit)
+		{	
+			if (init)
+			{   
+				hinit = init.syntaxCopy();
+				sv.hinit = init.syntaxCopy();
+			}
+		}
+		else
+			sv.hinit = hinit.syntaxCopy();
+	}
+		return sv;
+	}
+
+    void semantic(Scope sc)
+	{
+static if (false) {
+		printf("VarDeclaration.semantic('%s', parent = '%s')\n", toChars(), sc.parent.toChars());
+		printf(" type = %s\n", type ? type.toChars() : "null");
+		printf(" stc = x%x\n", sc.stc);
+		printf(" storage_class = x%x\n", storage_class);
+		printf("linkage = %d\n", sc.linkage);
+		//if (strcmp(toChars(), "mul") == 0) halt();
+}
+
+		storage_class |= sc.stc;
+		if (storage_class & STC.STCextern && init)
+			error("extern symbols cannot have initializers");
+		
+		/* If auto type inference, do the inference
+		 */
+		int inferred = 0;
+		if (!type)
+		{	
+			inuse++;
+			type = init.inferType(sc);
+			inuse--;
+			inferred = 1;
+
+			/* This is a kludge to support the existing syntax for RAII
+			 * declarations.
+			 */
+			storage_class &= ~STC.STCauto;
+			originalType = type;
+		}
+		else
+		{	
+			if (!originalType)
+				originalType = type;
+				
+			type = type.semantic(loc, sc);
+		}
+		//printf(" semantic type = %s\n", type ? type.toChars() : "null");
+
+		type.checkDeprecated(loc, sc);
+		linkage = sc.linkage;
+		this.parent = sc.parent;
+		//printf("this = %p, parent = %p, '%s'\n", this, parent, parent.toChars());
+		protection = sc.protection;
+		//printf("sc.stc = %x\n", sc.stc);
+		//printf("storage_class = x%x\n", storage_class);
+
+version (DMDV2) {
+		if (storage_class & STC.STCgshared && global.params.safe && !sc.module_.safe)
+		{
+		error("__gshared not allowed in safe mode; use shared");
+		}
+}
+
+		Dsymbol parent = toParent();
+		FuncDeclaration fd = parent.isFuncDeclaration();
+
+		Type tb = type.toBasetype();
+		if (tb.ty == TY.Tvoid && !(storage_class & STC.STClazy))
+		{	error("voids have no value");
+		type = Type.terror;
+		tb = type;
+		}
+		if (tb.ty == TY.Tfunction)
+		{	error("cannot be declared to be a function");
+		type = Type.terror;
+		tb = type;
+		}
+		if (tb.ty == TY.Tstruct)
+		{	TypeStruct ts = cast(TypeStruct)tb;
+
+		if (!ts.sym.members)
+		{
+			error("no definition of struct %s", ts.toChars());
+		}
+		}
+
+		if (tb.ty == TY.Ttuple)
+		{   /* Instead, declare variables for each of the tuple elements
+			* and add those.
+			*/
+		TypeTuple tt = cast(TypeTuple)tb;
+		size_t nelems = Argument.dim(tt.arguments);
+		Objects exps = new Objects();
+		exps.setDim(nelems);
+		Expression ie = init ? init.toExpression() : null;
+
+		for (size_t i = 0; i < nelems; i++)
+		{   Argument arg = Argument.getNth(tt.arguments, i);
+
+			OutBuffer buf;
+			buf.printf("_%s_field_%zu", ident.toChars(), i);
+			buf.writeByte(0);
+			string name = buf.extractString();
+			Identifier id = new Identifier(name, TOK.TOKidentifier);
+
+			Expression einit = ie;
+			if (ie && ie.op == TOK.TOKtuple)
+			{	einit = cast(Expression)(cast(TupleExp)ie).exps.data[i];
+			}
+			Initializer ti = init;
+			if (einit)
+			{	ti = new ExpInitializer(einit.loc, einit);
+			}
+
+			VarDeclaration v = new VarDeclaration(loc, arg.type, id, ti);
+			//printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars());
+			v.semantic(sc);
+
+			if (sc.scopesym)
+			{	//printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars());
+			if (sc.scopesym.members)
+				sc.scopesym.members.push(cast(void*)v);
+			}
+
+			Expression e = new DsymbolExp(loc, v);
+			exps.data[i] = cast(void*)e;
+		}
+		TupleDeclaration v2 = new TupleDeclaration(loc, ident, exps);
+		v2.isexp = 1;
+		aliassym = v2;
+		return;
+		}
+
+	Lagain:
+		/* Storage class can modify the type
+		 */
+		type = type.addStorageClass(storage_class);
+
+		/* Adjust storage class to reflect type
+		 */
+		if (type.isConst())
+		{	storage_class |= STC.STCconst;
+		if (type.isShared())
+			storage_class |= STC.STCshared;
+		}
+		else if (type.isInvariant())
+		storage_class |= STC.STCimmutable;
+		else if (type.isShared())
+		storage_class |= STC.STCshared;
+
+		if (isSynchronized())
+		{
+		error("variable %s cannot be synchronized", toChars());
+		}
+		else if (isOverride())
+		{
+		error("override cannot be applied to variable");
+		}
+		else if (isAbstract())
+		{
+		error("abstract cannot be applied to variable");
+		}
+		else if (storage_class & STC.STCfinal)
+		{
+		error("final cannot be applied to variable");
+		}
+
+		if (storage_class & (STC.STCstatic | STC.STCextern | STC.STCmanifest | STC.STCtemplateparameter | STC.STCtls | STC.STCgshared))
+		{
+		}
+		else
+		{
+		AggregateDeclaration aad = sc.anonAgg;
+		if (!aad)
+			aad = parent.isAggregateDeclaration();
+		if (aad)
+		{
+///version (DMDV2) {
+			assert(!(storage_class & (STC.STCextern | STC.STCstatic | STC.STCtls | STC.STCgshared)));
+
+			if (storage_class & (STC.STCconst | STC.STCimmutable) && init)
+			{
+			if (!type.toBasetype().isTypeBasic())
+				storage_class |= STC.STCstatic;
+			}
+			else
+///}
+			aad.addField(sc, this);
+		}
+
+		InterfaceDeclaration id = parent.isInterfaceDeclaration();
+		if (id)
+		{
+			error("field not allowed in interface");
+		}
+
+		/* Templates cannot add fields to aggregates
+		 */
+		TemplateInstance ti = parent.isTemplateInstance();
+		if (ti)
+		{
+			// Take care of nested templates
+			while (1)
+			{
+			TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
+			if (!ti2)
+				break;
+			ti = ti2;
+			}
+
+			// If it's a member template
+			AggregateDeclaration ad = ti.tempdecl.isMember();
+			if (ad && storage_class != STC.STCundefined)
+			{
+			error("cannot use template to add field to aggregate '%s'", ad.toChars());
+			}
+		}
+		}
+
+version (DMDV2) {
+		if ((storage_class & (STC.STCref | STC.STCparameter | STC.STCforeach)) == STC.STCref && ident != Id.This)
+		{
+			error("only parameters or foreach declarations can be ref");
+		}
+}
+
+		if (type.isauto() && !noauto)
+		{
+			if (storage_class & (STC.STCfield | STC.STCout | STC.STCref | STC.STCstatic | STC.STCmanifest | STC.STCtls | STC.STCgshared) || !fd)
+			{
+				error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
+			}
+
+			if (!(storage_class & (STC.STCauto | STC.STCscope)))
+			{
+				if (!(storage_class & STC.STCparameter) && ident != Id.withSym)
+				error("reference to scope class must be scope");
+			}
+		}
+
+		if ((isConst() || isInvariant()) && !init && !fd)
+		{
+			// Initialize by constructor only
+			storage_class |= STC.STCctorinit;
+		}
+
+		if (init)
+			storage_class |= STC.STCinit;     // remember we had an explicit initializer
+		else if (storage_class & STC.STCmanifest)
+			error("manifest constants must have initializers");
+
+		TOK op = TOK.TOKconstruct;
+		if (!init && !sc.inunion && !isStatic() && fd &&
+		(!(storage_class & (STC.STCfield | STC.STCin | STC.STCforeach | STC.STCparameter)) || (storage_class & STC.STCout)) &&
+		type.size() != 0)
+		{
+		// Provide a default initializer
+		//printf("Providing default initializer for '%s'\n", toChars());
+		if (type.ty == TY.Tstruct &&
+			(cast(TypeStruct)type).sym.zeroInit)
+		{   /* If a struct is all zeros, as a special case
+			 * set it's initializer to the integer 0.
+			 * In AssignExp.toElem(), we check for this and issue
+			 * a memset() to initialize the struct.
+			 * Must do same check in interpreter.
+			 */
+			Expression e = new IntegerExp(loc, 0, Type.tint32);
+			Expression e1;
+			e1 = new VarExp(loc, this);
+			e = new AssignExp(loc, e1, e);
+			e.op = TOK.TOKconstruct;
+			e.type = e1.type;		// don't type check this, it would fail
+			init = new ExpInitializer(loc, e);
+			return;
+		}
+		else if (type.ty == TY.Ttypedef)
+		{   TypeTypedef td = cast(TypeTypedef)type;
+			if (td.sym.init)
+			{	init = td.sym.init;
+			ExpInitializer ie = init.isExpInitializer();
+			if (ie)
+				// Make copy so we can modify it
+				init = new ExpInitializer(ie.loc, ie.exp);
+			}
+			else
+			init = getExpInitializer();
+		}
+		else
+		{
+			init = getExpInitializer();
+		}
+		// Default initializer is always a blit
+		op = TOK.TOKblit;
+		}
+
+		if (init)
+		{
+		sc = sc.push();
+		sc.stc &= ~(STC.STC_TYPECTOR | STC.STCpure | STC.STCnothrow | STC.STCref);
+
+		ArrayInitializer ai = init.isArrayInitializer();
+		if (ai && tb.ty == TY.Taarray)
+		{
+			init = ai.toAssocArrayInitializer();
+		}
+
+		StructInitializer si = init.isStructInitializer();
+		ExpInitializer ei = init.isExpInitializer();
+
+		// See if initializer is a NewExp that can be allocated on the stack
+		if (ei && isScope() && ei.exp.op == TOK.TOKnew)
+		{   NewExp ne = cast(NewExp)ei.exp;
+			if (!(ne.newargs && ne.newargs.dim))
+			{	ne.onstack = 1;
+			onstack = 1;
+			if (type.isBaseOf(ne.newtype.semantic(loc, sc), null))
+				onstack = 2;
+			}
+		}
+
+		// If inside function, there is no semantic3() call
+		if (sc.func)
+		{
+			// If local variable, use AssignExp to handle all the various
+			// possibilities.
+			if (fd &&
+			!(storage_class & (STC.STCmanifest | STC.STCstatic | STC.STCtls | STC.STCgshared | STC.STCextern)) &&
+			!init.isVoidInitializer())
+			{
+			//printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars());
+			if (!ei)
+			{
+				Expression e = init.toExpression();
+				if (!e)
+				{
+				init = init.semantic(sc, type);
+				e = init.toExpression();
+				if (!e)
+				{   error("is not a static and cannot have static initializer");
+					return;
+				}
+				}
+				ei = new ExpInitializer(init.loc, e);
+				init = ei;
+			}
+
+			Expression e1 = new VarExp(loc, this);
+
+			Type t = type.toBasetype();
+			if (t.ty == TY.Tsarray && !(storage_class & (STC.STCref | STC.STCout)))
+			{
+				ei.exp = ei.exp.semantic(sc);
+				if (!ei.exp.implicitConvTo(type))
+				{
+				int dim = cast(int)(cast(TypeSArray)t).dim.toInteger();	///
+				// If multidimensional static array, treat as one large array
+				while (1)
+				{
+					t = t.nextOf().toBasetype();
+					if (t.ty != TY.Tsarray)
+						break;
+					dim *= (cast(TypeSArray)t).dim.toInteger();
+					e1.type = new TypeSArray(t.nextOf(), new IntegerExp(Loc(0), dim, Type.tindex));
+				}
+				}
+				e1 = new SliceExp(loc, e1, null, null);
+			}
+			else if (t.ty == TY.Tstruct)
+			{
+				ei.exp = ei.exp.semantic(sc);
+version (DMDV2) {
+				/* Look to see if initializer is a call to the constructor
+				 */
+				StructDeclaration sd = (cast(TypeStruct)t).sym;
+				if (sd.ctor &&		// there are constructors
+				ei.exp.type.ty == TY.Tstruct &&	// rvalue is the same struct
+				(cast(TypeStruct)ei.exp.type).sym == sd &&
+				ei.exp.op == TOK.TOKstar)
+				{
+				/* Look for form of constructor call which is:
+				 *    *__ctmp.ctor(arguments...)
+				 */
+				PtrExp pe = cast(PtrExp)ei.exp;
+				if (pe.e1.op == TOK.TOKcall)
+				{   CallExp ce = cast(CallExp)pe.e1;
+					if (ce.e1.op == TOK.TOKdotvar)
+					{	DotVarExp dve = cast(DotVarExp)ce.e1;
+					if (dve.var.isCtorDeclaration())
+					{   /* It's a constructor call, currently constructing
+						 * a temporary __ctmp.
+						 */
+						/* Before calling the constructor, initialize
+						 * variable with a bit copy of the default
+						 * initializer
+						 */
+						Expression e = new AssignExp(loc, new VarExp(loc, this), t.defaultInit(loc));
+						e.op = TOK.TOKblit;
+						e.type = t;
+						ei.exp = new CommaExp(loc, e, ei.exp);
+
+						/* Replace __ctmp being constructed with e1
+						 */
+						dve.e1 = e1;
+						return;
+					}
+					}
+				}
+				}
+}
+				if (!ei.exp.implicitConvTo(type))
+				{	Type ti = ei.exp.type.toBasetype();
+				// Don't cast away invariant or mutability in initializer
+				if (!(ti.ty == TY.Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc)))
+					ei.exp = new CastExp(loc, ei.exp, type);
+				}
+			}
+			ei.exp = new AssignExp(loc, e1, ei.exp);
+			ei.exp.op = op;
+			canassign++;
+			ei.exp = ei.exp.semantic(sc);
+			canassign--;
+			ei.exp.optimize(WANT.WANTvalue);
+			}
+			else
+			{
+			init = init.semantic(sc, type);
+			}
+		}
+		else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) ||
+			 type.isConst() || type.isInvariant())
+		{
+			/* Because we may need the results of a const declaration in a
+			 * subsequent type, such as an array dimension, before semantic2()
+			 * gets ordinarily run, try to run semantic2() now.
+			 * Ignore failure.
+			 */
+
+			if (!global.errors && !inferred)
+			{
+			uint errors = global.errors;
+			global.gag++;
+			//printf("+gag\n");
+			Expression e;
+			Initializer i2 = init;
+			inuse++;
+			if (ei)
+			{
+				e = ei.exp.syntaxCopy();
+				e = e.semantic(sc);
+				e = e.implicitCastTo(sc, type);
+			}
+			else if (si || ai)
+			{   i2 = init.syntaxCopy();
+				i2 = i2.semantic(sc, type);
+			}
+			inuse--;
+			global.gag--;
+			//printf("-gag\n");
+			if (errors != global.errors)	// if errors happened
+			{
+				if (global.gag == 0)
+				global.errors = errors;	// act as if nothing happened
+version (DMDV2) {
+				/* Save scope for later use, to try again
+				 */
+				scope_ = new Scope(sc);
+				scope_.setNoFree();
+}
+			}
+			else if (ei)
+			{
+				if (isDataseg())
+					/* static const/invariant does CTFE
+					 */
+					e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret);
+				else
+					e = e.optimize(WANT.WANTvalue);
+				if (e.op == TOK.TOKint64 || e.op == TOK.TOKstring || e.op == TOK.TOKfloat64)
+				{
+					ei.exp = e;		// no errors, keep result
+				}
+///version (DMDV2) {
+				else
+				{
+				/* Save scope for later use, to try again
+				 */
+				scope_ = new Scope(sc);
+				scope_.setNoFree();
+				}
+///}
+			}
+			else
+				init = i2;		// no errors, keep result
+			}
+		}
+		sc = sc.pop();
+		}
+	}
+
+    void semantic2(Scope sc)
+	{
+		//printf("VarDeclaration.semantic2('%s')\n", toChars());
+		if (init && !toParent().isFuncDeclaration())
+		{	
+			inuse++;
+static if (false) {
+			ExpInitializer ei = init.isExpInitializer();
+			if (ei)
+			{
+				ei.exp.dump(0);
+				printf("type = %p\n", ei.exp.type);
+			}
+}
+			init = init.semantic(sc, type);
+			inuse--;
+		}
+	}
+
+    string kind()
+	{
+		return "variable";
+	}
+	
+    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		assert(false);
+	}
+	
+version (_DH) {
+    Type htype;
+    Initializer hinit;
+}
+    bool needThis()
+	{
+		//printf("VarDeclaration.needThis(%s, x%x)\n", toChars(), storage_class);
+		return (storage_class & STC.STCfield) != 0;
+	}
+	
+    bool isImportedSymbol()
+	{
+		if (protection == PROT.PROTexport && !init && (storage_class & STC.STCstatic || parent.isModule()))
+			return true;
+
+		return false;
+	}
+
+    bool isDataseg()
+	{
+static if (false) {
+		printf("VarDeclaration.isDataseg(%p, '%s')\n", this, toChars());
+		printf("%x, %p, %p\n", storage_class & (STC.STCstatic | STC.STCconst), parent.isModule(), parent.isTemplateInstance());
+		printf("parent = '%s'\n", parent.toChars());
+}
+		if (storage_class & STC.STCmanifest)
+			return false;
+
+		Dsymbol parent = this.toParent();
+		if (!parent && !(storage_class & STC.STCstatic))
+		{	
+			error("forward referenced");
+			type = Type.terror;
+			return false;
+		}
+
+		return canTakeAddressOf() && (storage_class & (STC.STCstatic | STC.STCextern | STC.STCtls | STC.STCgshared) || toParent().isModule() || toParent().isTemplateInstance());
+	}
+	
+    bool isThreadlocal()
+	{
+		//printf("VarDeclaration.isThreadlocal(%p, '%s')\n", this, toChars());
+static if (false) { /// || TARGET_OSX
+		/* To be thread-local, must use the __thread storage class.
+		 * BUG: OSX doesn't support thread local yet.
+		 */
+		return isDataseg() && (storage_class & (STC.STCtls | STC.STCconst | STC.STCimmutable | STC.STCshared | STC.STCgshared)) == STC.STCtls;
+} else {
+		/* Data defaults to being thread-local. It is not thread-local
+		 * if it is immutable, const or shared.
+		 */
+		bool i = isDataseg() && !(storage_class & (STC.STCimmutable | STC.STCconst | STC.STCshared | STC.STCgshared));
+		//printf("\treturn %d\n", i);
+		return i;
+}
+	}
+	
+    bool hasPointers()
+	{
+		//printf("VarDeclaration.hasPointers() %s, ty = %d\n", toChars(), type.ty);
+		return (!isDataseg() && type.hasPointers());
+	}
+	
+version (DMDV2) {
+    bool canTakeAddressOf()
+	{
+static if (false) {
+		/* Global variables and struct/class fields of the form:
+		 *	const int x = 3;
+		 * are not stored and hence cannot have their address taken.
+		 */
+		if ((isConst() || isInvariant()) && (storage_class & STC.STCinit) && (!(storage_class & (STC.STCstatic | STC.STCextern)) || (storage_class & STC.STCfield)) &&
+			(!parent || toParent().isModule() || toParent().isTemplateInstance()) && type.toBasetype().isTypeBasic())
+		{
+			return false;
+		}
+} else {
+		if (storage_class & STC.STCmanifest)
+			return false;
+}
+		return true;
+	}
+	
+    int needsAutoDtor()
+	{
+		assert(false);
+	}
+}
+
+	/******************************************
+	 * If a variable has an auto destructor call, return call for it.
+	 * Otherwise, return null.
+	 */
+    Expression callAutoDtor(Scope sc)
+	{
+		Expression e = null;
+
+		//printf("VarDeclaration.callAutoDtor() %s\n", toChars());
+
+		if (noauto || storage_class & STC.STCnodtor)
+			return null;
+
+		// Destructors for structs and arrays of structs
+		bool array = false;
+		Type tv = type.toBasetype();
+		while (tv.ty == TY.Tsarray)
+		{   
+			TypeSArray ta = cast(TypeSArray)tv;
+			array = true;
+			tv = tv.nextOf().toBasetype();
+		}
+		if (tv.ty == TY.Tstruct)
+		{   
+			TypeStruct ts = cast(TypeStruct)tv;
+			StructDeclaration sd = ts.sym;
+			if (sd.dtor)
+			{
+				if (array)
+				{
+					// Typeinfo.destroy(cast(void*)&v);
+					Expression ea = new SymOffExp(loc, this, 0, 0);
+					ea = new CastExp(loc, ea, Type.tvoid.pointerTo());
+					Expressions args = new Expressions();
+					args.push(cast(void*)ea);
+
+					Expression et = type.getTypeInfo(sc);
+					et = new DotIdExp(loc, et, Id.destroy);
+
+					e = new CallExp(loc, et, args);
+				}
+				else
+				{
+					e = new VarExp(loc, this);
+					e = new DotVarExp(loc, e, sd.dtor, 0);
+					e = new CallExp(loc, e);
+				}
+				return e;
+			}
+		}
+
+		// Destructors for classes
+		if (storage_class & (STC.STCauto | STC.STCscope))
+		{
+			for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass)
+			{
+				/* We can do better if there's a way with onstack
+				 * classes to determine if there's no way the monitor
+				 * could be set.
+				 */
+				//if (cd.isInterfaceDeclaration())
+				//error("interface %s cannot be scope", cd.toChars());
+				if (1 || onstack || cd.dtors.dim)	// if any destructors
+				{
+					// delete this;
+					Expression ec = new VarExp(loc, this);
+					e = new DeleteExp(loc, ec);
+					e.type = Type.tvoid;
+					break;
+				}
+			}
+		}
+		return e;
+	}
+
+	/****************************
+	 * Get ExpInitializer for a variable, if there is one.
+	 */
+    ExpInitializer getExpInitializer()
+	{
+		ExpInitializer ei;
+
+		if (init)
+			ei = init.isExpInitializer();
+		else
+		{
+			Expression e = type.defaultInit(loc);
+			if (e)
+				ei = new ExpInitializer(loc, e);
+			else
+				ei = null;
+		}
+		return ei;
+	}
+
+	/*******************************************
+	 * If variable has a constant expression initializer, get it.
+	 * Otherwise, return null.
+	 */
+    Expression getConstInitializer()
+	{
+		if ((isConst() || isInvariant() || storage_class & STC.STCmanifest) && storage_class & STC.STCinit)
+		{
+			ExpInitializer ei = getExpInitializer();
+			if (ei)
+				return ei.exp;
+		}
+
+		return null;
+	}
+
+    void checkCtorConstInit()
+	{
+	static if (false) { /* doesn't work if more than one static ctor */
+		if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield))
+			error("missing initializer in static constructor for const variable");
+	}
+	}
+
+	/************************************
+	 * Check to see if this variable is actually in an enclosing function
+	 * rather than the current one.
+	 */
+    void checkNestedReference(Scope sc, Loc loc)
+	{
+		if (parent && !isDataseg() && parent != sc.parent && !(storage_class & STC.STCmanifest))
+		{
+			// The function that this variable is in
+			FuncDeclaration fdv = toParent().isFuncDeclaration();
+			// The current function
+			FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
+
+			if (fdv && fdthis && fdv !is fdthis)
+			{
+				if (loc.filename)
+					fdthis.getLevel(loc, fdv);
+
+				for (int i = 0; i < nestedrefs.dim; i++)
+				{	
+					FuncDeclaration f = cast(FuncDeclaration)nestedrefs.data[i];
+					if (f == fdthis)
+						goto L1;
+				}
+				nestedrefs.push(cast(void*)fdthis);
+			  L1: ;
+
+				for (int i = 0; i < fdv.closureVars.dim; i++)
+				{	
+					Dsymbol s = cast(Dsymbol)fdv.closureVars.data[i];
+					if (s == this)
+						goto L2;
+				}
+
+				fdv.closureVars.push(cast(void*)this);
+			  L2: ;
+
+				//printf("fdthis is %s\n", fdthis.toChars());
+				//printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars());
+			}
+		}
+	}
+
+    Dsymbol toAlias()
+	{
+		//printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+		assert(this !is aliassym);
+		return aliassym ? aliassym.toAlias() : this;
+	}
+
+    Symbol* toSymbol()
+	{
+		//printf("VarDeclaration.toSymbol(%s)\n", toChars());
+		//if (needThis()) *(char*)0=0;
+		assert(!needThis());
+		if (!csym)
+		{	
+			Symbol* s;
+			TYPE* t;
+			string id;
+
+			if (isDataseg())
+				id = mangle();
+			else
+				id = ident.toChars();
+
+			s = symbol_calloc(toStringz(id));
+
+			if (storage_class & (STC.STCout | STC.STCref))
+			{
+				if (global.params.symdebug && storage_class & STC.STCparameter)
+				{
+					t = type_alloc(TYM.TYnptr);		// should be TYref, but problems in back end
+					t.Tnext = type.toCtype();
+					t.Tnext.Tcount++;
+				}
+				else
+					t = type_fake(TYM.TYnptr);
+			}
+			else if (storage_class & STC.STClazy)
+				t = type_fake(TYM.TYdelegate);		// Tdelegate as C type
+			else if (isParameter())
+				t = type.toCParamtype();
+			else
+				t = type.toCtype();
+
+			t.Tcount++;
+
+			if (isDataseg())
+			{
+				if (isThreadlocal())
+				{	
+					/* Thread local storage
+					 */
+					TYPE* ts = t;
+					ts.Tcount++;	// make sure a different t is allocated
+					type_setty(&t, t.Tty | mTY.mTYthread);
+					ts.Tcount--;
+
+					if (global.params.vtls)
+					{
+						string p = loc.toChars();
+						writef("%s: %s is thread local\n", p ? p : "", toChars());
+					}
+				}
+
+				s.Sclass = SC.SCextern;
+				s.Sfl = FL.FLextern;
+				slist_add(s);
+			}
+			else
+			{
+				s.Sclass = SC.SCauto;
+				s.Sfl = FL.FLauto;
+
+				if (nestedrefs.dim)
+				{
+					/* Symbol is accessed by a nested function. Make sure
+					 * it is not put in a register, and that the optimizer
+					 * assumes it is modified across function calls and pointer
+					 * dereferences.
+					 */
+					//printf("\tnested ref, not register\n");
+					type_setcv(&t, t.Tty | mTY.mTYvolatile);
+				}
+			}
+
+			mangle_t m = 0;
+			switch (linkage)
+			{
+				case LINK.LINKwindows:
+					m = mTYman.mTYman_std;
+					break;
+
+				case LINK.LINKpascal:
+					m = mTYman.mTYman_pas;
+					break;
+
+				case LINK.LINKc:
+					m = mTYman.mTYman_c;
+					break;
+
+				case LINK.LINKd:
+					m = mTYman.mTYman_d;
+					break;
+
+				case LINK.LINKcpp:
+					m = mTYman.mTYman_cpp;
+					break;
+
+				default:
+					writef("linkage = %d\n", linkage);
+					assert(0);
+			}
+			type_setmangle(&t, m);
+			s.Stype = t;
+
+			csym = s;
+		}
+		return csym;
+	}
+
+    void toObjFile(int multiobj)			// compile to .obj file
+	{
+		Symbol* s;
+		uint sz;
+		Dsymbol parent;
+
+		//printf("VarDeclaration.toObjFile(%p '%s' type=%s) protection %d\n", this, toChars(), type.toChars(), protection);
+		//printf("\talign = %d\n", type.alignsize());
+
+		if (aliassym)
+		{	
+			toAlias().toObjFile(0);
+			return;
+		}
+
+	version (DMDV2) {
+		// Do not store variables we cannot take the address of
+		if (!canTakeAddressOf())
+		{
+			return;
+		}
+	}
+
+		if (isDataseg() && !(storage_class & STC.STCextern))
+		{
+			s = toSymbol();
+			sz = cast(uint)type.size();
+
+			parent = this.toParent();
+///		version (DMDV1) {	/* private statics should still get a global symbol, in case
+///			 * another module inlines a function that references it.
+///			 */
+///			if (/*protection == PROT.PROTprivate ||*/
+///				!parent || parent.ident == null || parent.isFuncDeclaration())
+///			{
+///				s.Sclass = SC.SCstatic;
+///			}
+///			else
+///		}
+			{
+				if (storage_class & STC.STCcomdat)
+					s.Sclass = SC.SCcomdat;
+				else
+					s.Sclass = SC.SCglobal;
+
+				do
+				{
+					/* Global template data members need to be in comdat's
+					 * in case multiple .obj files instantiate the same
+					 * template with the same types.
+					 */
+					if (parent.isTemplateInstance() && !parent.isTemplateMixin())
+					{
+		version (DMDV1) {
+						/* These symbol constants have already been copied,
+						 * so no reason to output them.
+						 * Note that currently there is no way to take
+						 * the address of such a const.
+						 */
+						if (isConst() && type.toBasetype().ty != TY.Tsarray && init && init.isExpInitializer())
+							return;
+		}
+						s.Sclass = SC.SCcomdat;
+						break;
+					}
+					parent = parent.parent;
+				} while (parent);
+			}
+
+			s.Sfl = FL.FLdata;
+
+			if (init)
+			{   
+				s.Sdt = init.toDt();
+
+				// Look for static array that is block initialized
+				Type tb;
+				ExpInitializer ie = init.isExpInitializer();
+
+				tb = type.toBasetype();
+				if (tb.ty == TY.Tsarray && ie
+					&& !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf())
+					&& ie.exp.implicitConvTo(tb.nextOf()))
+				{
+					int dim = cast(int)(cast(TypeSArray)tb).dim.toInteger();
+
+					// Duplicate Sdt 'dim-1' times, as we already have the first one
+					while (--dim > 0)
+					{
+						ie.exp.toDt(&s.Sdt);
+					}
+				}
+			}
+			else if (storage_class & STC.STCextern)
+			{
+				s.Sclass = SC.SCextern;
+				s.Sfl = FL.FLextern;
+				s.Sdt = null;
+				// BUG: if isExport(), shouldn't we make it dllimport?
+				return;
+			}
+			else
+			{
+				type.toDt(&s.Sdt);
+			}
+			dt_optimize(s.Sdt);
+
+			// See if we can convert a comdat to a comdef,
+			// which saves on exe file space.
+			if (s.Sclass == SC.SCcomdat &&
+				s.Sdt &&
+				s.Sdt.dt == DT.DT_azeros &&
+				s.Sdt.DTnext is null &&
+				!isThreadlocal())
+			{
+				s.Sclass = SC.SCglobal;
+				s.Sdt.dt = DT.DT_common;
+			}
+
+		version (ELFOBJ_OR_MACHOBJ) { // Burton
+			if (s.Sdt && s.Sdt.dt == DT.DT_azeros && s.Sdt.DTnext is null)
+				s.Sseg = Segment.UDATA;
+			else
+				s.Sseg = Segment.DATA;
+		}
+			if (sz)
+			{   
+				outdata(s);
+				if (isExport())
+					obj_export(s, 0);
+			}
+		}
+	}
+
+    int cvMember(ubyte* p)
+	{
+		assert(false);
+	}
+
+    // Eliminate need for dynamic_cast
+    VarDeclaration isVarDeclaration() { return this; }
+}
\ No newline at end of file