diff dmd/FuncDeclaration.d @ 73:ef02e2e203c2

Updating to dmd2.033
author korDen
date Sat, 28 Aug 2010 19:42:41 +0400
parents 2e2a5c3f943a
children 7e0d548de9e6
line wrap: on
line diff
--- a/dmd/FuncDeclaration.d	Sat Aug 28 16:19:48 2010 +0200
+++ b/dmd/FuncDeclaration.d	Sat Aug 28 19:42:41 2010 +0400
@@ -4,6 +4,9 @@
 import dmd.DotIdExp;
 import dmd.AddrExp;
 import dmd.TryFinallyStatement;
+import dmd.TryCatchStatement;
+import dmd.Catch;
+import dmd.DeclarationStatement;
 import dmd.StaticDtorDeclaration;
 import dmd.GlobalExpressions;
 import dmd.PeelStatement;
@@ -80,7 +83,6 @@
 import dmd.Util;
 import dmd.BaseClass;
 import dmd.Module;
-import dmd.ILS;
 import dmd.InlineCostState;
 
 import dmd.expression.Util;
@@ -126,6 +128,10 @@
     Statement frequire;
     Statement fensure;
     Statement fbody;
+	
+    FuncDeclarations foverrides;	// functions this function overrides
+    FuncDeclaration fdrequire;		// function that does the in contract
+    FuncDeclaration fdensure;		// function that does the out contract
 
     Identifier outId;			// identifier for out statement
     VarDeclaration vresult;		// variable corresponding to outId
@@ -142,10 +148,10 @@
     DsymbolTable labtab;		// statement label symbol table
     Declaration overnext;		// next in overload list
     Loc endloc;				// location of closing curly bracket
-    int vtblIndex = -1;			// for member functions, index into vtbl[]
+    int vtblIndex;			// for member functions, index into vtbl[]
     int naked;				// !=0 if naked
     int inlineAsm;			// !=0 if has inline assembler
-    ILS inlineStatus = ILS.ILSuninitialized;
+    ILS inlineStatus;
     int inlineNest;			// !=0 if nested inline
     int cantInterpret;			// !=0 if cannot interpret function
     int semanticRun;			// 1 semantic() run
@@ -196,17 +202,52 @@
 		this.type = type;
 		this.loc = loc;
 		this.endloc = endloc;
-
+		fthrows = null;
+		frequire = null;
+		fdrequire = null;
+		fdensure = null;
+		outId = null;
+		vresult = null;
+		returnLabel = null;
+		fensure = null;
+		fbody = null;
+		localsymtab = null;
+		vthis = null;
+		v_arguments = null;
+version (IN_GCC) {
+		v_argptr = null;
+}
+		parameters = null;
+		labtab = null;
+		overnext = null;
+		vtblIndex = -1;
+		hasReturnExp = 0;
+		naked = 0;
+		inlineStatus = ILS.ILSuninitialized;
+		inlineNest = 0;
+		inlineAsm = 0;
+		cantInterpret = 0;
+		semanticRun = 0;
+version (DMDV1) {
+		nestedFrameRef = 0;
+}
+		fes = null;
+		introducing = 0;
+		tintro = null;
 		/* The type given for "infer the return type" is a TypeFunction with
 		 * null for the return type.
 		 */
 		inferRetType = (type && type.nextOf() is null);
-
+		hasReturnExp = 0;
+		nrvo_can = 1;
+		nrvo_var = null;
+		shidden = null;
+version (DMDV2) {
+		builtin = BUILTINunknown;
+		tookAddressOf = 0;
+}
+		foverrides = new FuncDeclarations();
 		closureVars = new Dsymbols();
-
-version (DMDV2) {
-		builtin = BUILTIN.BUILTINunknown;
-}
 	}
 	
     override Dsymbol syntaxCopy(Dsymbol s)
@@ -551,6 +592,10 @@
 			}
 			cd.vtbl.data[vi] = cast(void*)this;
 			vtblIndex = vi;
+			
+			/* Remember which functions this overrides
+			 */
+			foverrides.push(cast(void*)fdv);
 
 			/* This works by whenever this function is called,
 			 * it actually returns tintro, which gets dynamically
@@ -597,9 +642,13 @@
 			default:
 			{   FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi];
 				Type ti = null;
+				
+				/* Remember which functions this overrides
+				 */
+				foverrides.push(cast(void*)fdv);
 
 				if (fdv.tintro)
-				ti = fdv.tintro;
+					ti = fdv.tintro;
 				else if (!type.equals(fdv.type))
 				{
 				/* Only need to have a tintro if the vptr
@@ -727,6 +776,61 @@
 			}
 		}
 		}
+		
+		if (isVirtual())
+		{
+			/* Rewrite contracts as nested functions, then call them.
+			 * Doing it as nested functions means that overriding functions
+			 * can call them.
+			 */
+			if (frequire)
+			{   
+				/*   in { ... }
+				 * becomes:
+				 *   void __require() { ... }
+				 *   __require();
+				 */
+				Loc loc = frequire.loc;
+				TypeFunction tf = new TypeFunction(null, Type.tvoid, 0, LINKd);
+				FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf);
+				fd.fbody = frequire;
+				Statement s1 = new DeclarationStatement(loc, fd);
+				Expression e = new CallExp(loc, new VarExp(loc, fd, 0), cast(Expressions)null);
+				Statement s2 = new ExpStatement(loc, e);
+				frequire = new CompoundStatement(loc, s1, s2);
+				fdrequire = fd;
+			}
+
+			if (fensure)
+			{   /*   out (result) { ... }
+				 * becomes:
+				 *   tret __ensure(ref tret result) { ... }
+				 *   __ensure(result);
+				 */
+				if (!outId && f.nextOf().toBasetype().ty != Tvoid)
+					outId = Id.result;	// provide a default
+
+				Loc loc = fensure.loc;
+				Arguments arguments = new Arguments();
+				Argument a = null;
+				if (outId)
+				{	
+					a = new Argument(STCref, f.nextOf(), outId, null);
+					arguments.push(cast(void*)a);
+				}
+				TypeFunction tf = new TypeFunction(arguments, Type.tvoid, 0, LINKd);
+				FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf);
+				fd.fbody = fensure;
+				Statement s1 = new DeclarationStatement(loc, fd);
+				Expression eresult = null;
+				if (outId)
+					eresult = new IdentifierExp(loc, outId);
+				Expression e = new CallExp(loc, new VarExp(loc, fd, 0), eresult);
+				Statement s2 = new ExpStatement(loc, e);
+				fensure = new CompoundStatement(loc, s1, s2);
+				fdensure = fd;
+			}
+		}
 
 	Ldone:
 		/* Save scope for possible later use (if we need the
@@ -790,6 +894,9 @@
 			error("can only throw classes, not %s", t.toChars());
 		}
 		}
+		
+	    frequire = mergeFrequire(frequire);
+		fensure = mergeFensure(fensure);
 
 		if (fbody || frequire)
 		{
@@ -1328,27 +1435,29 @@
 			if (argptr)
 			{	// Initialize _argptr to point past non-variadic arg
 version (IN_GCC) {
-			// Handled in FuncDeclaration.toObjFile
-			v_argptr = argptr;
-			v_argptr.init = new VoidInitializer(loc);
+				// Handled in FuncDeclaration.toObjFile
+				v_argptr = argptr;
+				v_argptr.init = new VoidInitializer(loc);
 } else {
-			Expression e1;
-			Expression e;
-			Type t = argptr.type;
-			VarDeclaration p;
-			uint offset;
-
-			e1 = new VarExp(Loc(0), argptr);
-			if (parameters && parameters.dim)
-				p = cast(VarDeclaration)parameters.data[parameters.dim - 1];
-			else
-				p = v_arguments;		// last parameter is _arguments[]
-			offset = cast(uint)p.type.size();	///
-			offset = (offset + 3) & ~3;	// assume stack aligns on 4
-			e = new SymOffExp(Loc(0), p, offset);
-			e = new AssignExp(Loc(0), e1, e);
-			e.type = t;
-			a.push(cast(void*)new ExpStatement(Loc(0), e));
+				Type t = argptr.type;
+				VarDeclaration p;
+				uint offset;
+
+				Expression e1 = new VarExp(Loc(0), argptr);
+				if (parameters && parameters.dim)
+					p = cast(VarDeclaration)parameters.data[parameters.dim - 1];
+				else
+					p = v_arguments;		// last parameter is _arguments[]
+				if (p.storage_class & STClazy)
+					// If the last parameter is lazy, it's the size of a delegate
+					offset = PTRSIZE * 2;
+				else
+					offset = cast(size_t)p.type.size();
+				offset = (offset + 3) & ~3;	// assume stack aligns on 4
+				Expression e = new SymOffExp(Loc(0), p, offset);
+				e = new AssignExp(Loc(0), e1, e);
+				e.type = t;
+				a.push(cast(void*)new ExpStatement(Loc(0), e));
 }
 			}
 
@@ -2767,6 +2876,99 @@
 		return true;
 	}
 	
+    /****************************************************
+	 * Merge into this function the 'in' contracts of all it overrides.
+	 * 'in's are OR'd together, i.e. only one of them needs to pass.
+	 */
+
+	Statement mergeFrequire(Statement sf)
+	{
+		/* Implementing this is done by having the overriding function call
+		 * nested functions (the fdrequire functions) nested inside the overridden
+		 * function. This requires that the stack layout of the calling function's
+		 * parameters and 'this' pointer be in the same place (as the nested
+		 * function refers to them).
+		 * This is easy for the parameters, as they are all on the stack in the same
+		 * place by definition, since it's an overriding function. The problem is
+		 * getting the 'this' pointer in the same place, since it is a local variable.
+		 * We did some hacks in the code generator to make this happen:
+		 *	1. always generate exception handler frame, or at least leave space for it
+		 *     in the frame (Windows 32 SEH only)
+		 *	2. always generate an EBP style frame
+		 *  3. since 'this' is passed in a register that is subsequently copied into
+		 *     a stack local, allocate that local immediately following the exception
+		 *     handler block, so it is always at the same offset from EBP.
+		 */
+		for (int i = 0; i < foverrides.dim; i++)
+		{
+			FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i];
+			sf = fdv.mergeFrequire(sf);
+			if (fdv.frequire)
+			{
+				//printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+				/* Make the call:
+				 *   try { __require(); }
+				 *   catch { frequire; }
+				 */
+				Expression eresult = null;
+				Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, 0), eresult);
+				Statement s2 = new ExpStatement(loc, e);
+
+				if (sf)
+				{	
+					Catch c = new Catch(loc, null, null, sf);
+					Array catches = new Array();
+					catches.push(cast(void*)c);
+					sf = new TryCatchStatement(loc, s2, catches);
+				}
+				else
+					sf = s2;
+			}
+		}
+		return sf;
+	}
+
+    /****************************************************
+	 * Merge into this function the 'out' contracts of all it overrides.
+	 * 'out's are AND'd together, i.e. all of them need to pass.
+	 */
+
+	Statement mergeFensure(Statement sf)
+	{
+		/* Same comments as for mergeFrequire(), except that we take care
+		 * of generating a consistent reference to the 'result' local by
+		 * explicitly passing 'result' to the nested function as a reference
+		 * argument.
+		 * This won't work for the 'this' parameter as it would require changing
+		 * the semantic code for the nested function so that it looks on the parameter
+		 * list for the 'this' pointer, something that would need an unknown amount
+		 * of tweaking of various parts of the compiler that I'd rather leave alone.
+		 */
+		for (int i = 0; i < foverrides.dim; i++)
+		{
+			FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i];
+			sf = fdv.mergeFensure(sf);
+			if (fdv.fensure)
+			{
+				//printf("fdv.fensure: %s\n", fdv.fensure.toChars());
+				// Make the call: __ensure(result)
+				Expression eresult = null;
+				if (outId)
+					eresult = new IdentifierExp(loc, outId);
+				Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, 0), eresult);
+				Statement s2 = new ExpStatement(loc, e);
+
+				if (sf)
+				{
+					sf = new CompoundStatement(fensure.loc, s2, sf);
+				}
+				else
+					sf = s2;
+			}
+		}
+		return sf;
+	}
+	
     static FuncDeclaration genCfunc(Type treturn, string name)
 	{
 		return genCfunc(treturn, Lexer.idPool(name));
@@ -2991,6 +3193,16 @@
 
 		s = func.toSymbol();
 		f = s.Sfunc;
+		
+version (TARGET_WINDOS) {
+    /* This is done so that the 'this' pointer on the stack is the same
+     * distance away from the function parameters, so that an overriding
+     * function can call the nested fdensure or fdrequire of its overridden function
+     * and the stack offsets are the same.
+     */
+    if (isVirtual() && (fensure || frequire))
+		f.Fflags3 |= F3.Ffakeeh;
+}
 
 version (TARGET_OSX) {
 		s.Sclass = SC.SCcomdat;