diff dmd/expression/Util.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 5c9b78899f5d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/expression/Util.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,1363 @@
+module dmd.expression.Util;
+
+import dmd.Expression;
+import dmd.Loc;
+import dmd.BUILTIN;
+import dmd.Scope;
+import dmd.FuncExp;
+import dmd.DelegateExp;
+import dmd.LINK;
+import dmd.NullExp;
+import dmd.SymOffExp;
+import dmd.ExpInitializer;
+import dmd.Lexer;
+import dmd.TypeSArray;
+import dmd.TypeArray;
+import dmd.VarDeclaration;
+import dmd.VoidInitializer;
+import dmd.DeclarationExp;
+import dmd.VarExp;
+import dmd.NewExp;
+import dmd.STC;
+import dmd.WANT;
+import dmd.IndexExp;
+import dmd.AssignExp;
+import dmd.CommaExp;
+import dmd.Argument;
+import dmd.DefaultInitExp;
+import dmd.Identifier;
+import dmd.Dsymbol;
+import dmd.Global;
+import dmd.ScopeDsymbol;
+import dmd.DotIdExp;
+import dmd.DotVarExp;
+import dmd.CallExp;
+import dmd.TY;
+import dmd.MATCH;
+import dmd.TypeFunction;
+import dmd.declaration.Match;
+import dmd.ArrayTypes;
+import dmd.Declaration;
+import dmd.FuncAliasDeclaration;
+import dmd.AliasDeclaration;
+import dmd.FuncDeclaration;
+import dmd.TemplateDeclaration;
+import dmd.AggregateDeclaration;
+import dmd.IntegerExp;
+import dmd.Type;
+import dmd.TOK;
+import dmd.TypeExp;
+import dmd.TypeTuple;
+import dmd.TupleExp;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.ClassDeclaration;
+import dmd.TypeClass;
+import dmd.StructDeclaration;
+import dmd.TypeStruct;
+import dmd.MOD;
+import dmd.PROT;
+import dmd.PREC;
+import dmd.Util;
+import dmd.TypeAArray;
+import dmd.Id;
+
+import std.stdio : writef;
+
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+Expression build_overload(Loc loc, Scope sc, Expression ethis, Expression earg, Identifier id)
+{
+    Expression e;
+
+    //printf("build_overload(id = '%s')\n", id.toChars());
+    //earg.print();
+    //earg.type.print();
+    e = new DotIdExp(loc, ethis, id);
+
+    if (earg)
+		e = new CallExp(loc, e, earg);
+    else
+		e = new CallExp(loc, e);
+
+    e = e.semantic(sc);
+    return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+
+Dsymbol search_function(ScopeDsymbol ad, Identifier funcid)
+{
+    Dsymbol s;
+    FuncDeclaration fd;
+    TemplateDeclaration td;
+
+    s = ad.search(Loc(0), funcid, 0);
+    if (s)
+    {
+		Dsymbol s2;
+
+		//printf("search_function: s = '%s'\n", s.kind());
+		s2 = s.toAlias();
+		//printf("search_function: s2 = '%s'\n", s2.kind());
+		fd = s2.isFuncDeclaration();
+		if (fd && fd.type.ty == TY.Tfunction)
+			return fd;
+
+		td = s2.isTemplateDeclaration();
+		if (td)
+			return td;
+    }
+
+    return null;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+
+/***************************************************
+ * Visit each overloaded function in turn, and call
+ * dg(param, f) on it.
+ * Exit when no more, or dg(param, f) returns 1.
+ * Returns:
+ *	0	continue
+ *	1	done
+ */
+
+int overloadApply(FuncDeclaration fstart, int delegate(FuncDeclaration) dg)
+{
+    FuncDeclaration f;
+    Declaration d;
+    Declaration next;
+
+    for (d = fstart; d; d = next)
+    {	
+		FuncAliasDeclaration fa = d.isFuncAliasDeclaration();
+
+		if (fa)
+		{
+			if (overloadApply(fa.funcalias, dg))
+				return 1;
+			next = fa.overnext;
+		}
+		else
+		{
+			AliasDeclaration a = d.isAliasDeclaration();
+
+			if (a)
+			{
+				Dsymbol s = a.toAlias();
+				next = s.isDeclaration();
+				if (next is a)
+					break;
+				if (next is fstart)
+					break;
+			}
+			else
+			{
+				f = d.isFuncDeclaration();
+				if (f is null)
+				{  
+					d.error("is aliased to a function");
+					break;		// BUG: should print error message?
+				}
+				if (dg(f))
+					return 1;
+
+				next = f.overnext;
+			}
+		}
+    }
+    return 0;
+}
+
+/********************************************
+ * Decide which function matches the arguments best.
+ */
+
+struct Param2
+{
+    Match* m;
+    Expression ethis;
+    Expressions arguments;
+	
+	int fp2(FuncDeclaration f)
+	{   
+		MATCH match;
+
+		if (f != m.lastf)		// skip duplicates
+		{
+			m.anyf = f;
+			TypeFunction tf = cast(TypeFunction)f.type;
+			match = tf.callMatch(f.needThis() ? ethis : null, arguments);
+			//printf("match = %d\n", match);
+			if (match != MATCH.MATCHnomatch)
+			{
+				if (match > m.last)
+					goto LfIsBetter;
+
+				if (match < m.last)
+					goto LlastIsBetter;
+
+				/* See if one of the matches overrides the other.
+				 */
+				if (m.lastf.overrides(f))
+					goto LlastIsBetter;
+				else if (f.overrides(m.lastf))
+					goto LfIsBetter;
+
+				/* Try to disambiguate using template-style partial ordering rules.
+				 * In essence, if f() and g() are ambiguous, if f() can call g(),
+				 * but g() cannot call f(), then pick f().
+				 * This is because f() is "more specialized."
+				 */
+				{
+					MATCH c1 = f.leastAsSpecialized(m.lastf);
+					MATCH c2 = m.lastf.leastAsSpecialized(f);
+					//printf("c1 = %d, c2 = %d\n", c1, c2);
+					if (c1 > c2)
+						goto LfIsBetter;
+					if (c1 < c2)
+						goto LlastIsBetter;
+				}
+
+			Lambiguous:
+				m.nextf = f;
+				m.count++;
+				return 0;
+
+			LfIsBetter:
+				m.last = match;
+				m.lastf = f;
+				m.count = 1;
+				return 0;
+
+			LlastIsBetter:
+				return 0;
+			}
+		}
+		return 0;
+	}
+}
+
+struct Param1
+{
+    Type t;		// type to match
+    FuncDeclaration f;	// return value
+	
+	int fp1(FuncDeclaration f)
+	{   
+		if (t.equals(f.type))
+		{	
+			this.f = f;
+			return 1;
+		}
+
+	version (DMDV2) {
+		/* Allow covariant matches, if it's just a const conversion
+		 * of the return type
+		 */
+		if (t.ty == Tfunction)
+		{   
+			TypeFunction tf = cast(TypeFunction)f.type;
+			if (tf.covariant(t) == 1 &&
+				tf.nextOf().implicitConvTo(t.nextOf()) >= MATCHconst)
+			{
+				this.f = f;
+				return 1;
+			}
+		}
+	}
+		return 0;
+	}
+}
+
+void overloadResolveX(Match* m, FuncDeclaration fstart, Expression ethis, Expressions arguments)
+{
+    Param2 p;
+    p.m = m;
+    p.ethis = ethis;
+    p.arguments = arguments;
+    overloadApply(fstart, &p.fp2);
+}
+
+void templateResolve(Match* m, TemplateDeclaration td, Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions arguments)
+{
+    FuncDeclaration fd;
+
+    assert(td);
+    fd = td.deduceFunctionTemplate(sc, loc, targsi, ethis, arguments);
+    if (!fd)
+		return;
+    m.anyf = fd;
+    if (m.last >= MATCH.MATCHexact)
+    {
+		m.nextf = fd;
+		m.count++;
+    }
+    else
+    {
+		m.last = MATCH.MATCHexact;
+		m.lastf = fd;
+		m.count = 1;
+    }
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+void arrayExpressionSemantic(Expressions exps, Scope sc)
+{
+    if (exps)
+    {
+		for (size_t i = 0; i < exps.dim; i++)
+		{   
+			Expression e = cast(Expression)exps.data[i];
+
+			e = e.semantic(sc);
+			exps.data[i] = cast(void*)e;
+		}
+    }
+}
+
+/****************************************
+ * Preprocess arguments to function.
+ */
+
+void preFunctionArguments(Loc loc, Scope sc, Expressions exps)
+{
+    if (exps)
+    {
+		expandTuples(exps);
+
+		for (size_t i = 0; i < exps.dim; i++)
+		{   
+			Expression arg = cast(Expression)exps.data[i];
+
+			if (!arg.type)
+			{
+debug {
+				if (!global.gag)
+					writef("1: \n");
+}
+				arg.error("%s is not an expression", arg.toChars());
+				arg = new IntegerExp(arg.loc, 0, Type.tint32);
+			}
+
+			arg = resolveProperties(sc, arg);
+			exps.data[i] = cast(void*) arg;
+
+			//arg.rvalue();
+static if (false) {
+			if (arg.type.ty == TY.Tfunction)
+			{
+				arg = new AddrExp(arg.loc, arg);
+				arg = arg.semantic(sc);
+				exps.data[i] = cast(void*) arg;
+			}
+}
+		}
+    }
+}
+
+/*************************************************************
+ * Given var, we need to get the
+ * right 'this' pointer if var is in an outer class, but our
+ * existing 'this' pointer is in an inner class.
+ * Input:
+ *	e1	existing 'this'
+ *	ad	struct or class we need the correct 'this' for
+ *	var	the specific member of ad we're accessing
+ */
+
+Expression getRightThis(Loc loc, Scope sc, AggregateDeclaration ad, Expression e1, Declaration var)
+{
+	//printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
+ L1:
+    Type t = e1.type.toBasetype();
+    //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
+
+    /* If e1 is not the 'this' pointer for ad
+     */
+    if (ad && !(t.ty == TY.Tpointer && t.nextOf().ty == TY.Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == TY.Tstruct && (cast(TypeStruct)t).sym == ad))
+    {
+		ClassDeclaration cd = ad.isClassDeclaration();
+		ClassDeclaration tcd = t.isClassHandle();
+
+		/* e1 is the right this if ad is a base class of e1
+		 */
+		if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
+		{
+			/* Only classes can be inner classes with an 'outer'
+			 * member pointing to the enclosing class instance
+			 */
+			if (tcd && tcd.isNested())
+			{   
+				/* e1 is the 'this' pointer for an inner class: tcd.
+				 * Rewrite it as the 'this' pointer for the outer class.
+				 */
+
+				e1 = new DotVarExp(loc, e1, tcd.vthis);
+				e1.type = tcd.vthis.type;
+				// Do not call checkNestedRef()
+				//e1 = e1.semantic(sc);
+
+				// Skip up over nested functions, and get the enclosing
+				// class type.
+				int n = 0;
+				Dsymbol s;
+				for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent())
+				{   
+					FuncDeclaration f = s.isFuncDeclaration();
+					if (f.vthis)
+					{
+						//printf("rewriting e1 to %s's this\n", f.toChars());
+						n++;
+						e1 = new VarExp(loc, f.vthis);
+					}
+				}
+				if (s && s.isClassDeclaration())
+				{   
+					e1.type = s.isClassDeclaration().type;
+					if (n > 1)
+						e1 = e1.semantic(sc);
+				}
+				else
+					e1 = e1.semantic(sc);
+				goto L1;
+			}
+			/* Can't find a path from e1 to ad
+			 */
+			e1.error("this for %s needs to be type %s not type %s", var.toChars(), ad.toChars(), t.toChars());
+		}
+    }
+    return e1;
+}
+
+/*******************************************
+ * Given a symbol that could be either a FuncDeclaration or
+ * a function template, resolve it to a function symbol.
+ *	sc		instantiation scope
+ *	loc		instantiation location
+ *	targsi		initial list of template arguments
+ *	ethis		if !null, the 'this' pointer argument
+ *	fargs		arguments to function
+ *	flags		1: do not issue error message on no match, just return null
+ */
+
+FuncDeclaration resolveFuncCall(Scope sc, Loc loc, Dsymbol s,
+	Objects tiargs,
+	Expression ethis,
+	Expressions arguments,
+	int flags)
+{
+	if (!s)
+		return null;			// no match
+    FuncDeclaration f = s.isFuncDeclaration();
+    if (f)
+		f = f.overloadResolve(loc, ethis, arguments);
+    else
+    {	
+		TemplateDeclaration td = s.isTemplateDeclaration();
+		assert(td);
+		f = td.deduceFunctionTemplate(sc, loc, tiargs, null, arguments, flags);
+    }
+    return f;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ *	1. implicitly convert argument to the corresponding parameter type
+ *	2. add default arguments for any missing arguments
+ *	3. do default promotions on arguments corresponding to ...
+ *	4. add hidden _arguments[] argument
+ *	5. call copy constructor for struct value arguments
+ */
+
+void functionArguments(Loc loc, Scope sc, TypeFunction tf, Expressions arguments)
+{
+	uint n;
+
+    //printf("functionArguments()\n");
+    assert(arguments);
+    size_t nargs = arguments ? arguments.dim : 0;
+    size_t nparams = Argument.dim(tf.parameters);
+
+    if (nargs > nparams && tf.varargs == 0)
+	error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf.toChars());
+
+    n = (nargs > nparams) ? nargs : nparams;	// n = max(nargs, nparams)
+
+    int done = 0;
+    for (size_t i = 0; i < n; i++)
+    {
+		Expression arg;
+
+		if (i < nargs)
+			arg = cast(Expression)arguments.data[i];
+		else
+			arg = null;
+
+		Type tb;
+
+		if (i < nparams)
+		{
+			Argument p = Argument.getNth(tf.parameters, i);
+
+			if (!arg)
+			{
+				if (!p.defaultArg)
+				{
+					if (tf.varargs == 2 && i + 1 == nparams)
+						goto L2;
+
+					error(loc, "expected %d function arguments, not %d", nparams, nargs);
+					break;
+				}
+				arg = p.defaultArg;
+version (DMDV2) {
+				if (arg.op == TOK.TOKdefault)
+				{   
+					DefaultInitExp de = cast(DefaultInitExp)arg;
+					arg = de.resolve(loc, sc);
+				}
+				else
+				{
+					arg = arg.copy();
+				}
+} else {
+				arg = arg.copy();
+}
+				arguments.push(cast(void*)arg);
+				nargs++;
+			}
+
+			if (tf.varargs == 2 && i + 1 == nparams)
+			{
+				//printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
+				if (arg.implicitConvTo(p.type))
+				{
+					if (nargs != nparams)
+						error(loc, "expected %zu function arguments, not %zu", nparams, nargs);
+					goto L1;
+				}
+				 L2:
+				tb = p.type.toBasetype();		///
+				Type tret = p.isLazyArray();
+				switch (tb.ty)
+				{
+					case TY.Tsarray:
+					case TY.Tarray:
+					{	// Create a static array variable v of type arg.type
+version (IN_GCC) {
+						/* GCC 4.0 does not like zero length arrays used like
+						   this; pass a null array value instead. Could also
+						   just make a one-element array. */
+						if (nargs - i == 0)
+						{
+							arg = new NullExp(loc);
+							break;
+						}
+}
+						Identifier id = Lexer.uniqueId("__arrayArg");
+						Type t = new TypeSArray((cast(TypeArray)tb).next, new IntegerExp(nargs - i));
+						t = t.semantic(loc, sc);
+						VarDeclaration v = new VarDeclaration(loc, t, id, new VoidInitializer(loc));
+						v.semantic(sc);
+						v.parent = sc.parent;
+						//sc.insert(v);
+
+						Expression c = new DeclarationExp(Loc(0), v);
+						c.type = v.type;
+
+						for (size_t u = i; u < nargs; u++)
+						{   
+							Expression a = cast(Expression)arguments.data[u];
+							if (tret && !(cast(TypeArray)tb).next.equals(a.type))
+								a = a.toDelegate(sc, tret);
+
+							Expression e = new VarExp(loc, v);
+							e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams));
+							AssignExp ae = new AssignExp(loc, e, a);
+
+			version (DMDV2) {
+							ae.op = TOK.TOKconstruct;
+			}
+
+							if (c)
+								c = new CommaExp(loc, c, ae);
+							else
+								c = ae;
+						}
+
+						arg = new VarExp(loc, v);
+						if (c)
+							arg = new CommaExp(loc, c, arg);
+						break;
+					}
+
+					case TY.Tclass:
+					{	/* Set arg to be:
+						 *	new Tclass(arg0, arg1, ..., argn)
+						 */
+						Expressions args = new Expressions();
+						args.setDim(nargs - i);
+						for (size_t u = i; u < nargs; u++)
+							args.data[u - i] = arguments.data[u];
+						arg = new NewExp(loc, null, null, p.type, args);
+						break;
+					}
+
+					default:
+						if (!arg)
+						{   
+							error(loc, "not enough arguments");
+							return;
+						}
+						break;
+				}
+
+				arg = arg.semantic(sc);
+				//printf("\targ = '%s'\n", arg.toChars());
+				arguments.setDim(i + 1);
+				done = 1;
+			}
+
+		L1:
+			if (!(p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid))
+			{
+				if (p.type != arg.type)
+				{
+					//printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
+					arg = arg.implicitCastTo(sc, p.type);
+					arg = arg.optimize(WANT.WANTvalue);
+				}
+			}
+			if (p.storageClass & STC.STCref)
+			{
+				arg = arg.toLvalue(sc, arg);
+			}
+			else if (p.storageClass & STC.STCout)
+			{
+				arg = arg.modifiableLvalue(sc, arg);
+			}
+
+			// Convert static arrays to pointers
+			tb = arg.type.toBasetype();
+			if (tb.ty == TY.Tsarray)
+			{
+				arg = arg.checkToPointer();
+			}
+version (DMDV2) {
+			if (tb.ty == TY.Tstruct && !(p.storageClass & (STC.STCref | STC.STCout)))
+			{
+				arg = callCpCtor(loc, sc, arg);
+			}
+}
+
+			// Convert lazy argument to a delegate
+			if (p.storageClass & STC.STClazy)
+			{
+				arg = arg.toDelegate(sc, p.type);
+			}
+version (DMDV2) {
+			/* Look for arguments that cannot 'escape' from the called
+			 * function.
+			 */
+			if (!tf.parameterEscapes(p))
+			{
+				/* Function literals can only appear once, so if this
+				 * appearance was scoped, there cannot be any others.
+				 */
+				if (arg.op == TOK.TOKfunction)
+				{   
+					FuncExp fe = cast(FuncExp)arg;
+					fe.fd.tookAddressOf = 0;
+				}
+
+				/* For passing a delegate to a scoped parameter,
+				 * this doesn't count as taking the address of it.
+				 * We only worry about 'escaping' references to the function.
+				 */
+				else if (arg.op == TOK.TOKdelegate)
+				{   
+					DelegateExp de = cast(DelegateExp)arg;
+					if (de.e1.op == TOK.TOKvar)
+					{	
+						VarExp ve = cast(VarExp)de.e1;
+						FuncDeclaration f = ve.var.isFuncDeclaration();
+						if (f)
+						{   
+							f.tookAddressOf--;
+							//printf("tookAddressOf = %d\n", f.tookAddressOf);
+						}
+					}
+				}
+			}
+}
+		}
+		else
+		{
+			// If not D linkage, do promotions
+			if (tf.linkage != LINK.LINKd)
+			{
+				// Promote bytes, words, etc., to ints
+				arg = arg.integralPromotions(sc);
+
+				// Promote floats to doubles
+				switch (arg.type.ty)
+				{
+					case TY.Tfloat32:
+						arg = arg.castTo(sc, Type.tfloat64);
+						break;
+
+					case TY.Timaginary32:
+						arg = arg.castTo(sc, Type.timaginary64);
+						break;
+					default:
+						break;
+				}
+			}
+
+			// Convert static arrays to dynamic arrays
+			tb = arg.type.toBasetype();
+			if (tb.ty == TY.Tsarray)
+			{	
+				TypeSArray ts = cast(TypeSArray)tb;
+				Type ta = ts.next.arrayOf();
+				if (ts.size(arg.loc) == 0)
+				{   
+					arg = new NullExp(arg.loc);
+					arg.type = ta;
+				}
+				else
+				{
+					arg = arg.castTo(sc, ta);
+				}
+			}
+version (DMDV2) {
+			if (tb.ty == TY.Tstruct)
+			{
+				arg = callCpCtor(loc, sc, arg);
+			}
+
+			// Give error for overloaded function addresses
+			if (arg.op == TOK.TOKsymoff)
+			{	
+				SymOffExp se = cast(SymOffExp)arg;
+				if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
+					arg.error("function %s is overloaded", arg.toChars());
+			}
+}
+			arg.rvalue();
+		}
+		arg = arg.optimize(WANT.WANTvalue);
+		arguments.data[i] = cast(void*) arg;
+		if (done)
+			break;
+    }
+
+    // If D linkage and variadic, add _arguments[] as first argument
+    if (tf.linkage == LINK.LINKd && tf.varargs == 1)
+    {
+		Expression e = createTypeInfoArray(sc, cast(Expression*)&arguments.data[nparams], arguments.dim - nparams);
+		arguments.insert(0, cast(void*)e);
+    }
+}
+
+/****************************************
+ * Expand tuples.
+ */
+
+void expandTuples(Expressions exps)
+{
+    //printf("expandTuples()\n");
+    if (exps)
+    {
+		for (size_t i = 0; i < exps.dim; i++)
+		{   
+			Expression arg = cast(Expression)exps.data[i];
+			if (!arg)
+				continue;
+
+			// Look for tuple with 0 members
+			if (arg.op == TOK.TOKtype)
+			{	
+				TypeExp e = cast(TypeExp)arg;
+				if (e.type.toBasetype().ty == TY.Ttuple)
+				{   
+					TypeTuple tt = cast(TypeTuple)e.type.toBasetype();
+
+					if (!tt.arguments || tt.arguments.dim == 0)
+					{
+						exps.remove(i);
+						if (i == exps.dim)
+							return;
+						i--;
+						continue;
+					}
+				}
+			}
+
+			// Inline expand all the tuples
+			while (arg.op == TOK.TOKtuple)
+			{	
+				TupleExp te = cast(TupleExp)arg;
+
+				exps.remove(i);		// remove arg
+				exps.insert(i, cast(void*)te.exps);	// replace with tuple contents
+
+				if (i == exps.dim)
+					return;		// empty tuple, no more arguments
+
+				arg = cast(Expression)exps.data[i];
+			}
+		}
+    }
+}
+
+/**************************************************
+ * Write out argument types to buf.
+ */
+
+void argExpTypesToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs)
+{
+    if (arguments)
+    {	
+		scope OutBuffer argbuf = new OutBuffer();
+
+		for (size_t i = 0; i < arguments.dim; i++)
+		{   
+			Expression arg = cast(Expression)arguments.data[i];
+
+			if (i)
+				buf.writeByte(',');
+
+			argbuf.reset();
+			arg.type.toCBuffer2(argbuf, hgs, MOD.MODundefined);
+			buf.write(argbuf);
+		}
+    }
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+
+bool hasPackageAccess(Scope sc, Dsymbol s)
+{
+version (LOG) {
+    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc);
+}
+
+    for (; s; s = s.parent)
+    {
+		if (s.isPackage() && !s.isModule())
+			break;
+    }
+version (LOG) {
+    if (s)
+		printf("\tthis is in package '%s'\n", s.toChars());
+}
+
+    if (s && s == sc.module_.parent)
+    {
+version (LOG) {
+		printf("\ts is in same package as sc\n");
+}
+		return true;
+    }
+
+
+version (LOG) {
+    printf("\tno package access\n");
+}
+
+    return false;
+}
+
+/*********************************************
+ * Call copy constructor for struct value argument.
+ */
+version (DMDV2) {
+	Expression callCpCtor(Loc loc, Scope sc, Expression e)
+	{
+		Type tb = e.type.toBasetype();
+		assert(tb.ty == Tstruct);
+		StructDeclaration sd = (cast(TypeStruct)tb).sym;
+		if (sd.cpctor)
+		{
+			/* Create a variable tmp, and replace the argument e with:
+			 *	(tmp = e),tmp
+			 * and let AssignExp() handle the construction.
+			 * This is not the most efficent, ideally tmp would be constructed
+			 * directly onto the stack.
+			 */
+			Identifier idtmp = Lexer.uniqueId("__tmp");
+			VarDeclaration tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(Loc(0), e));
+			Expression ae = new DeclarationExp(loc, tmp);
+			e = new CommaExp(loc, ae, new VarExp(loc, tmp));
+			e = e.semantic(sc);
+		}
+		return e;
+	}
+}
+
+/***************************************
+ * Create a static array of TypeInfo references
+ * corresponding to an array of Expression's.
+ * Used to supply hidden _arguments[] value for variadic D functions.
+ */
+
+Expression createTypeInfoArray(Scope sc, Expression* exps, int dim)
+{
+	assert(false);
+}
+
+/**************************************
+ * Evaluate builtin function.
+ * Return result: null if cannot evaluate it.
+ */
+
+Expression eval_builtin(BUILTIN builtin, Expressions arguments)
+{
+	assert(false);
+}
+
+Expression fromConstInitializer(int result, Expression e1)
+{
+    //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
+    //static int xx; if (xx++ == 10) assert(0);
+    Expression e = e1;
+    if (e1.op == TOK.TOKvar)
+    {	
+		VarExp ve = cast(VarExp)e1;
+		VarDeclaration v = ve.var.isVarDeclaration();
+		e = expandVar(result, v);
+		if (e)
+		{   
+			if (e.type != e1.type)
+			{   
+				// Type 'paint' operation
+				e = e.copy();
+				e.type = e1.type;
+			}
+		}
+		else
+		{
+			e = e1;
+		}
+    }
+    return e;
+}
+
+/*************************************
+ * If variable has a const initializer,
+ * return that initializer.
+ */
+
+Expression expandVar(int result, VarDeclaration v)
+{
+	//printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null");
+
+    Expression e = null;
+    if (!v)
+		return e;
+
+    if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest)
+    {
+		if (!v.type)
+		{
+			//error("ICE");
+			return e;
+		}
+
+		Type tb = v.type.toBasetype();
+		if (result & WANT.WANTinterpret || v.storage_class & STC.STCmanifest || (tb.ty != TY.Tsarray && tb.ty != TY.Tstruct))
+		{
+			if (v.init)
+			{
+				if (v.inuse)
+				{   
+					if (v.storage_class & STC.STCmanifest)
+						v.error("recursive initialization of constant");
+					goto L1;
+				}
+				Expression ei = v.init.toExpression();
+				if (!ei)
+					goto L1;
+				if (ei.op == TOK.TOKconstruct || ei.op == TOK.TOKblit)
+				{   
+					AssignExp ae = cast(AssignExp)ei;
+					ei = ae.e2;
+					if (ei.isConst() != 1 && ei.op != TOK.TOKstring)
+						goto L1;
+					if (ei.type != v.type)
+						goto L1;
+				}
+				if (v.scope_)
+				{
+					v.inuse++;
+					e = ei.syntaxCopy();
+					e = e.semantic(v.scope_);
+					e = e.implicitCastTo(v.scope_, v.type);
+					// enabling this line causes test22 in test suite to fail
+					//ei.type = e.type;
+					v.scope_ = null;
+					v.inuse--;
+				}
+				else if (!ei.type)
+				{
+					goto L1;
+				}
+				else
+					// Should remove the copy() operation by
+					// making all mods to expressions copy-on-write
+					e = ei.copy();
+			}
+			else
+			{
+static if (true) {
+			goto L1;
+} else {
+			// BUG: what if const is initialized in constructor?
+			e = v.type.defaultInit();
+			e.loc = e1.loc;
+}
+			}
+			if (e.type != v.type)
+			{
+				e = e.castTo(null, v.type);
+			}
+			v.inuse++;
+			e = e.optimize(result);
+			v.inuse--;
+		}
+    }
+L1:
+    //if (e) printf("\te = %s, e.type = %s\n", e.toChars(), e.type.toChars());
+    return e;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ */
+
+void accessCheck(Loc loc, Scope sc, Expression e, Declaration d)
+{
+version (LOG) {
+    if (e)
+    {	
+		printf("accessCheck(%s . %s)\n", e.toChars(), d.toChars());
+		printf("\te.type = %s\n", e.type.toChars());
+    }
+    else
+    {
+		//printf("accessCheck(%s)\n", d.toChars());
+    }
+}
+    if (!e)
+    {
+		if (d.prot() == PROT.PROTprivate && d.getModule() != sc.module_ ||
+			d.prot() == PROT.PROTpackage && !hasPackageAccess(sc, d))
+
+			error(loc, "%s %s.%s is not accessible from %s",
+			d.kind(), d.getModule().toChars(), d.toChars(), sc.module_.toChars());
+    }
+    else if (e.type.ty == TY.Tclass)
+    {   
+		// Do access check
+		ClassDeclaration cd;
+
+		cd = cast(ClassDeclaration)((cast(TypeClass)e.type).sym);
+static if (true) {
+		if (e.op == TOK.TOKsuper)
+		{   
+			ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration();
+			if (cd2)
+				cd = cd2;
+		}
+}
+		cd.accessCheck(loc, sc, d);
+    }
+    else if (e.type.ty == TY.Tstruct)
+    {   
+		// Do access check
+		StructDeclaration cd = cast(StructDeclaration)((cast(TypeStruct)e.type).sym);
+		cd.accessCheck(loc, sc, d);
+    }
+}
+
+/*****************************************
+ * Given array of arguments and an aggregate type,
+ * if any of the argument types are missing, attempt to infer
+ * them from the aggregate type.
+ */
+
+void inferApplyArgTypes(TOK op, Arguments arguments, Expression aggr)
+{
+    if (!arguments || !arguments.dim)
+		return;
+
+    /* Return if no arguments need types.
+     */
+    for (size_t u = 0; 1; u++)
+    {	
+		if (u == arguments.dim)
+			return;
+
+		Argument arg = cast(Argument)arguments.data[u];
+		if (!arg.type)
+			break;
+    }
+
+    AggregateDeclaration ad;
+
+    Argument arg = cast(Argument)arguments.data[0];
+    Type taggr = aggr.type;
+    if (!taggr)
+		return;
+    Type tab = taggr.toBasetype();
+    switch (tab.ty)
+    {
+		case TY.Tarray:
+		case TY.Tsarray:
+		case TY.Ttuple:
+			if (arguments.dim == 2)
+			{
+				if (!arg.type)
+					arg.type = Type.tsize_t;	// key type
+				arg = cast(Argument)arguments.data[1];
+			}
+			if (!arg.type && tab.ty != TY.Ttuple)
+				arg.type = tab.nextOf();	// value type
+			break;
+
+		case TY.Taarray:
+		{   
+			TypeAArray taa = cast(TypeAArray)tab;
+
+			if (arguments.dim == 2)
+			{
+				if (!arg.type)
+					arg.type = taa.index;	// key type
+				arg = cast(Argument)arguments.data[1];
+			}
+			if (!arg.type)
+				arg.type = taa.next;		// value type
+			break;
+		}
+
+		case TY.Tclass:
+			ad = (cast(TypeClass)tab).sym;
+			goto Laggr;
+
+		case TY.Tstruct:
+			ad = (cast(TypeStruct)tab).sym;
+			goto Laggr;
+
+		Laggr:
+			if (arguments.dim == 1)
+			{
+				if (!arg.type)
+				{
+					/* Look for a head() or rear() overload
+					 */
+					Identifier id = (op == TOK.TOKforeach) ? Id.Fhead : Id.Ftoe;
+					Dsymbol s = search_function(ad, id);
+					FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
+					if (!fd)
+					{	
+						if (s && s.isTemplateDeclaration())
+							break;
+						goto Lapply;
+					}
+					arg.type = fd.type.nextOf();
+				}
+				break;
+			}
+
+		Lapply:
+		{   /* Look for an
+			 *	int opApply(int delegate(ref Type [, ...]) dg);
+			 * overload
+			 */
+			Dsymbol s = search_function(ad, (op == TOK.TOKforeach_reverse) ? Id.applyReverse : Id.apply);
+			if (s)
+			{
+				FuncDeclaration fd = s.isFuncDeclaration();
+				if (fd) 
+				{   
+					inferApplyArgTypesX(fd, arguments);
+					break;
+				}
+static if (false) {
+				TemplateDeclaration td = s.isTemplateDeclaration();
+				if (td)
+				{   
+					inferApplyArgTypesZ(td, arguments);
+					break;
+				}
+}
+			}
+			break;
+		}
+
+		case TY.Tdelegate:
+		{
+			if (0 && aggr.op == TOK.TOKdelegate)
+			{	
+				DelegateExp de = cast(DelegateExp)aggr;
+
+				FuncDeclaration fd = de.func.isFuncDeclaration();
+				if (fd)
+					inferApplyArgTypesX(fd, arguments);
+				}
+			else
+			{
+				inferApplyArgTypesY(cast(TypeFunction)tab.nextOf(), arguments);
+			}
+			break;
+		}
+
+		default:
+			break;		// ignore error, caught later
+    }
+}
+
+struct Param3
+{
+	/********************************
+	 * Recursive helper function,
+	 * analogous to func.overloadResolveX().
+	 */
+
+	int fp3(FuncDeclaration f)
+	{
+		TypeFunction tf = cast(TypeFunction)f.type;
+		if (inferApplyArgTypesY(tf, arguments) == 1)
+			return 0;
+
+		if (arguments.dim == 0)
+			return 1;
+
+		return 0;
+	}
+	
+	Arguments arguments;
+}
+
+void inferApplyArgTypesX(FuncDeclaration fstart, Arguments arguments)
+{
+	Param3 p3;
+	p3.arguments = arguments;
+    overloadApply(fstart, &p3.fp3);
+}
+
+/******************************
+ * Infer arguments from type of function.
+ * Returns:
+ *	0 match for this function
+ *	1 no match for this function
+ */
+
+int inferApplyArgTypesY(TypeFunction tf, Arguments arguments)
+{   
+	size_t nparams;
+    Argument p;
+
+    if (Argument.dim(tf.parameters) != 1)
+		goto Lnomatch;
+
+    p = Argument.getNth(tf.parameters, 0);
+    if (p.type.ty != TY.Tdelegate)
+		goto Lnomatch;
+
+    tf = cast(TypeFunction)p.type.nextOf();
+    assert(tf.ty == TY.Tfunction);
+
+    /* We now have tf, the type of the delegate. Match it against
+     * the arguments, filling in missing argument types.
+     */
+    nparams = Argument.dim(tf.parameters);
+    if (nparams == 0 || tf.varargs)
+		goto Lnomatch;		// not enough parameters
+    if (arguments.dim != nparams)
+		goto Lnomatch;		// not enough parameters
+
+    for (size_t u = 0; u < nparams; u++)
+    {
+		Argument arg = cast(Argument)arguments.data[u];
+		Argument param = Argument.getNth(tf.parameters, u);
+		if (arg.type)
+		{   
+			if (!arg.type.equals(param.type))
+			{
+				/* Cannot resolve argument types. Indicate an
+				 * error by setting the number of arguments to 0.
+				 */
+				arguments.dim = 0;
+				goto Lmatch;
+			}
+			continue;
+		}
+		arg.type = param.type;
+    }
+
+  Lmatch:
+    return 0;
+
+  Lnomatch:
+    return 1;
+}
+
+/**************************************************
+ * Write expression out to buf, but wrap it
+ * in ( ) if its precedence is less than pr.
+ */
+
+void expToCBuffer(OutBuffer buf, HdrGenState* hgs, Expression e, PREC pr)
+{
+    //if (precedence[e.op] == 0) e.dump(0);
+    if (precedence[e.op] < pr ||
+	/* Despite precedence, we don't allow a<b<c expressions.
+	 * They must be parenthesized.
+	 */
+	(pr == PREC.PREC_rel && precedence[e.op] == pr))
+    {
+		buf.writeByte('(');
+		e.toCBuffer(buf, hgs);
+		buf.writeByte(')');
+    }
+    else
+		e.toCBuffer(buf, hgs);
+}
+
+/**************************************************
+ * Write out argument list to buf.
+ */
+
+void argsToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs)
+{
+    if (arguments)
+    {
+		for (size_t i = 0; i < arguments.dim; i++)
+		{   
+			Expression arg = cast(Expression)arguments.data[i];
+
+			if (arg)
+			{	
+				if (i)
+					buf.writeByte(',');
+				expToCBuffer(buf, hgs, arg, PREC.PREC_assign);
+			}
+		}
+    }
+}
\ No newline at end of file