changeset 336:aaade6ded589 trunk

[svn r357] Merged DMD 1.033
author lindquist
date Sat, 12 Jul 2008 19:38:31 +0200
parents 17b844102023
children d03d748a9b5f
files dmd/access.c dmd/aggregate.h dmd/attrib.c dmd/attrib.h dmd/cast.c dmd/class.c dmd/clone.c dmd/constfold.c dmd/declaration.c dmd/declaration.h dmd/doc.c dmd/dsymbol.c dmd/dsymbol.h dmd/enum.c dmd/enum.h dmd/expression.c dmd/expression.h dmd/func.c dmd/id.c dmd/id.h dmd/idgen.c dmd/import.c dmd/import.h dmd/init.c dmd/inline.c dmd/interpret.c dmd/lexer.c dmd/lexer.h dmd/mars.c dmd/mars.h dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/optimize.c dmd/parse.c dmd/parse.h dmd/root.c dmd/root.h dmd/statement.c dmd/statement.h dmd/staticassert.c dmd/staticassert.h dmd/stringtable.c dmd/stringtable.h dmd/struct.c dmd/template.c dmd/template.h dmd/version.c dmd/version.h gen/asmstmt.cpp gen/classes.cpp gen/dvalue.cpp gen/functions.cpp gen/structs.cpp gen/toir.cpp gen/toobj.cpp gen/typinf.cpp premake.lua
diffstat 59 files changed, 18358 insertions(+), 16984 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/access.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/access.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,423 +1,424 @@
-
-// Copyright (c) 1999-2006 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "root.h"
-#include "mem.h"
-
-#include "enum.h"
-#include "aggregate.h"
-#include "init.h"
-#include "attrib.h"
-#include "scope.h"
-#include "id.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "expression.h"
-#include "module.h"
-
-#define LOG 0
-
-/* Code to do access checks
- */
-
-int hasPackageAccess(Scope *sc, Dsymbol *s);
-
-/****************************************
- * Return PROT access for Dsymbol smember in this declaration.
- */
-
-enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
-{
-    return PROTpublic;
-}
-
-enum PROT StructDeclaration::getAccess(Dsymbol *smember)
-{
-    enum PROT access_ret = PROTnone;
-
-#if LOG
-    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
-	toChars(), smember->toChars());
-#endif
-    if (smember->toParent() == this)
-    {
-	access_ret = smember->prot();
-    }
-    else if (smember->isDeclaration()->isStatic())
-    {
-	access_ret = smember->prot();
-    }
-    return access_ret;
-}
-
-enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
-{
-    enum PROT access_ret = PROTnone;
-
-#if LOG
-    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
-	toChars(), smember->toChars());
-#endif
-    if (smember->toParent() == this)
-    {
-	access_ret = smember->prot();
-    }
-    else
-    {
-	enum PROT access;
-	int i;
-
-	if (smember->isDeclaration()->isStatic())
-	{
-	    access_ret = smember->prot();
-	}
-
-	for (i = 0; i < baseclasses.dim; i++)
-	{   BaseClass *b = (BaseClass *)baseclasses.data[i];
-
-	    access = b->base->getAccess(smember);
-	    switch (access)
-	    {
-		case PROTnone:
-		    break;
-
-		case PROTprivate:
-		    access = PROTnone;	// private members of base class not accessible
-		    break;
-
-		case PROTpackage:
-		case PROTprotected:
-		case PROTpublic:
-		case PROTexport:
-		    // If access is to be tightened
-		    if (b->protection < access)
-			access = b->protection;
-
-		    // Pick path with loosest access
-		    if (access > access_ret)
-			access_ret = access;
-		    break;
-
-		default:
-		    assert(0);
-	    }
-	}
-    }
-#if LOG
-    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
-	toChars(), smember->toChars(), access_ret);
-#endif
-    return access_ret;
-}
-
-/********************************************************
- * Helper function for ClassDeclaration::accessCheck()
- * Returns:
- *	0	no access
- * 	1	access
- */
-
-static int accessCheckX(
-	Dsymbol *smember,
-	Dsymbol *sfunc,
-	AggregateDeclaration *dthis,
-	AggregateDeclaration *cdscope)
-{
-    assert(dthis);
-
-#if 0
-    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
-	dthis->toChars(), smember->toChars(),
-	sfunc ? sfunc->toChars() : "NULL",
-	cdscope ? cdscope->toChars() : "NULL");
-#endif
-    if (dthis->hasPrivateAccess(sfunc) ||
-	dthis->isFriendOf(cdscope))
-    {
-	if (smember->toParent() == dthis)
-	    return 1;
-	else
-	{
-	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
-	    if (cdthis)
-	    {
-		for (int i = 0; i < cdthis->baseclasses.dim; i++)
-		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
-		    enum PROT access;
-
-		    access = b->base->getAccess(smember);
-		    if (access >= PROTprotected ||
-			accessCheckX(smember, sfunc, b->base, cdscope)
-		       )
-			return 1;
-
-		}
-	    }
-	}
-    }
-    else
-    {
-	if (smember->toParent() != dthis)
-	{
-	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
-	    if (cdthis)
-	    {
-		for (int i = 0; i < cdthis->baseclasses.dim; i++)
-		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
-
-		    if (accessCheckX(smember, sfunc, b->base, cdscope))
-			return 1;
-		}
-	    }
-	}
-    }
-    return 0;
-}
-
-/*******************************
- * Do access check for member of this class, this class being the
- * type of the 'this' pointer used to access smember.
- */
-
-void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
-{
-    int result;
-
-    FuncDeclaration *f = sc->func;
-    AggregateDeclaration *cdscope = sc->getStructClassScope();
-    enum PROT access;
-
-#if LOG
-    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
-	toChars(), smember->toChars(),
-	f ? f->toChars() : NULL,
-	cdscope ? cdscope->toChars() : NULL);
-#endif
-
-    Dsymbol *smemberparent = smember->toParent();
-    if (!smemberparent || !smemberparent->isAggregateDeclaration())
-    {
-#if LOG
-	printf("not an aggregate member\n");
-#endif
-	return;				// then it is accessible
-    }
-
-    // BUG: should enable this check
-    //assert(smember->parent->isBaseOf(this, NULL));
-
-    if (smemberparent == this)
-    {	enum PROT access = smember->prot();
-
-	result = access >= PROTpublic ||
-		hasPrivateAccess(f) ||
-		isFriendOf(cdscope) ||
-		(access == PROTpackage && hasPackageAccess(sc, this));
-#if LOG
-	printf("result1 = %d\n", result);
-#endif
-    }
-    else if ((access = this->getAccess(smember)) >= PROTpublic)
-    {
-	result = 1;
-#if LOG
-	printf("result2 = %d\n", result);
-#endif
-    }
-    else if (access == PROTpackage && hasPackageAccess(sc, this))
-    {
-	result = 1;
-#if LOG
-	printf("result3 = %d\n", result);
-#endif
-    }
-    else
-    {
-	result = accessCheckX(smember, f, this, cdscope);
-#if LOG
-	printf("result4 = %d\n", result);
-#endif
-    }
-    if (!result)
-    {
-	error(loc, "member %s is not accessible", smember->toChars());
-    }
-}
-
-/****************************************
- * Determine if this is the same or friend of cd.
- */
-
-int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
-{
-#if LOG
-    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
-#endif
-    if (this == cd)
-	return 1;
-
-    // Friends if both are in the same module
-    //if (toParent() == cd->toParent())
-    if (cd && getModule() == cd->getModule())
-    {
-#if LOG
-	printf("\tin same module\n");
-#endif
-	return 1;
-    }
-
-#if LOG
-    printf("\tnot friend\n");
-#endif
-    return 0;
-}
-
-/****************************************
- * Determine if scope sc has package level access to s.
- */
-
-int hasPackageAccess(Scope *sc, Dsymbol *s)
-{
-#if LOG
-    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
-#endif
-
-    for (; s; s = s->parent)
-    {
-	if (s->isPackage() && !s->isModule())
-	    break;
-    }
-#if LOG
-    if (s)
-	printf("\tthis is in package '%s'\n", s->toChars());
-#endif
-
-    if (s && s == sc->module->parent)
-    {
-#if LOG
-	printf("\ts is in same package as sc\n");
-#endif
-	return 1;
-    }
-
-
-#if LOG
-    printf("\tno package access\n");
-#endif
-    return 0;
-}
-
-/**********************************
- * Determine if smember has access to private members of this declaration.
- */
-
-int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
-{
-    if (smember)
-    {	AggregateDeclaration *cd = NULL;
-	Dsymbol *smemberparent = smember->toParent();
-	if (smemberparent)
-	    cd = smemberparent->isAggregateDeclaration();
-
-#if LOG
-	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
-		toChars(), smember->toChars());
-#endif
-
-	if (this == cd)		// smember is a member of this class
-	{
-#if LOG
-	    printf("\tyes 1\n");
-#endif
-	    return 1;		// so we get private access
-	}
-
-	// If both are members of the same module, grant access
-	while (1)
-	{   Dsymbol *sp = smember->toParent();
-	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
-		smember = sp;
-	    else
-		break;
-	}
-	if (!cd && toParent() == smember->toParent())
-	{
-#if LOG
-	    printf("\tyes 2\n");
-#endif
-	    return 1;
-	}
-	if (!cd && getModule() == smember->getModule())
-	{
-#if LOG
-	    printf("\tyes 3\n");
-#endif
-	    return 1;
-	}
-    }
-#if LOG
-    printf("\tno\n");
-#endif
-    return 0;
-}
-
-/****************************************
- * Check access to d for expression e.d
- */
-
-void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
-{
-#if 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());
-    }
-#endif
-    if (!e)
-    {
-	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
-	    d->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 == Tclass)
-    {   // Do access check
-	ClassDeclaration *cd;
-
-	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
-#if 1
-	if (e->op == TOKsuper)
-	{   ClassDeclaration *cd2;
-
-	    cd2 = sc->func->toParent()->isClassDeclaration();
-	    if (cd2)
-		cd = cd2;
-	}
-#endif
-	cd->accessCheck(loc, sc, d);
-    }
-    else if (e->type->ty == Tstruct)
-    {   // Do access check
-	StructDeclaration *cd;
-
-	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
-	cd->accessCheck(loc, sc, d);
-    }
-}
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "scope.h"
+#include "id.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "module.h"
+
+#define LOG 0
+
+/* Code to do access checks
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s);
+
+/****************************************
+ * Return PROT access for Dsymbol smember in this declaration.
+ */
+
+enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
+{
+    return PROTpublic;
+}
+
+enum PROT StructDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else if (smember->isDeclaration()->isStatic())
+    {
+	access_ret = smember->prot();
+    }
+    return access_ret;
+}
+
+enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else
+    {
+	enum PROT access;
+	int i;
+
+	if (smember->isDeclaration()->isStatic())
+	{
+	    access_ret = smember->prot();
+	}
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{   BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    access = b->base->getAccess(smember);
+	    switch (access)
+	    {
+		case PROTnone:
+		    break;
+
+		case PROTprivate:
+		    access = PROTnone;	// private members of base class not accessible
+		    break;
+
+		case PROTpackage:
+		case PROTprotected:
+		case PROTpublic:
+		case PROTexport:
+		    // If access is to be tightened
+		    if (b->protection < access)
+			access = b->protection;
+
+		    // Pick path with loosest access
+		    if (access > access_ret)
+			access_ret = access;
+		    break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+#if LOG
+    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
+	toChars(), smember->toChars(), access_ret);
+#endif
+    return access_ret;
+}
+
+/********************************************************
+ * Helper function for ClassDeclaration::accessCheck()
+ * Returns:
+ *	0	no access
+ * 	1	access
+ */
+
+static int accessCheckX(
+	Dsymbol *smember,
+	Dsymbol *sfunc,
+	AggregateDeclaration *dthis,
+	AggregateDeclaration *cdscope)
+{
+    assert(dthis);
+
+#if 0
+    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
+	dthis->toChars(), smember->toChars(),
+	sfunc ? sfunc->toChars() : "NULL",
+	cdscope ? cdscope->toChars() : "NULL");
+#endif
+    if (dthis->hasPrivateAccess(sfunc) ||
+	dthis->isFriendOf(cdscope))
+    {
+	if (smember->toParent() == dthis)
+	    return 1;
+	else
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+		    enum PROT access;
+
+		    access = b->base->getAccess(smember);
+		    if (access >= PROTprotected ||
+			accessCheckX(smember, sfunc, b->base, cdscope)
+		       )
+			return 1;
+
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (smember->toParent() != dthis)
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+
+		    if (accessCheckX(smember, sfunc, b->base, cdscope))
+			return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ */
+
+void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
+{
+    int result;
+
+    FuncDeclaration *f = sc->func;
+    AggregateDeclaration *cdscope = sc->getStructClassScope();
+    enum PROT access;
+
+#if LOG
+    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
+	toChars(), smember->toChars(),
+	f ? f->toChars() : NULL,
+	cdscope ? cdscope->toChars() : NULL);
+#endif
+
+    Dsymbol *smemberparent = smember->toParent();
+    if (!smemberparent || !smemberparent->isAggregateDeclaration())
+    {
+#if LOG
+	printf("not an aggregate member\n");
+#endif
+	return;				// then it is accessible
+    }
+
+    // BUG: should enable this check
+    //assert(smember->parent->isBaseOf(this, NULL));
+
+    if (smemberparent == this)
+    {	enum PROT access = smember->prot();
+
+	result = access >= PROTpublic ||
+		hasPrivateAccess(f) ||
+		isFriendOf(cdscope) ||
+		(access == PROTpackage && hasPackageAccess(sc, this));
+#if LOG
+	printf("result1 = %d\n", result);
+#endif
+    }
+    else if ((access = this->getAccess(smember)) >= PROTpublic)
+    {
+	result = 1;
+#if LOG
+	printf("result2 = %d\n", result);
+#endif
+    }
+    else if (access == PROTpackage && hasPackageAccess(sc, this))
+    {
+	result = 1;
+#if LOG
+	printf("result3 = %d\n", result);
+#endif
+    }
+    else
+    {
+	result = accessCheckX(smember, f, this, cdscope);
+#if LOG
+	printf("result4 = %d\n", result);
+#endif
+    }
+    if (!result)
+    {
+	error(loc, "member %s is not accessible", smember->toChars());
+halt();
+    }
+}
+
+/****************************************   
+ * Determine if this is the same or friend of cd.
+ */
+
+int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
+{
+#if LOG
+    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
+#endif
+    if (this == cd)
+	return 1;
+
+    // Friends if both are in the same module
+    //if (toParent() == cd->toParent())
+    if (cd && getModule() == cd->getModule())
+    {
+#if LOG
+	printf("\tin same module\n");
+#endif
+	return 1;
+    }
+
+#if LOG
+    printf("\tnot friend\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+#if LOG
+    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
+#endif
+
+    for (; s; s = s->parent)
+    {
+	if (s->isPackage() && !s->isModule())
+	    break;
+    }
+#if LOG
+    if (s)
+	printf("\tthis is in package '%s'\n", s->toChars());
+#endif
+
+    if (s && s == sc->module->parent)
+    {
+#if LOG
+	printf("\ts is in same package as sc\n");
+#endif
+	return 1;
+    }
+
+
+#if LOG
+    printf("\tno package access\n");
+#endif
+    return 0;
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+
+int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
+{
+    if (smember)
+    {	AggregateDeclaration *cd = NULL;
+	Dsymbol *smemberparent = smember->toParent();
+	if (smemberparent)
+	    cd = smemberparent->isAggregateDeclaration();
+
+#if LOG
+	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
+		toChars(), smember->toChars());
+#endif
+
+	if (this == cd)		// smember is a member of this class
+	{
+#if LOG
+	    printf("\tyes 1\n");
+#endif
+	    return 1;		// so we get private access
+	}
+
+	// If both are members of the same module, grant access
+	while (1)
+	{   Dsymbol *sp = smember->toParent();
+	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
+		smember = sp;
+	    else
+		break;
+	}
+	if (!cd && toParent() == smember->toParent())
+	{
+#if LOG
+	    printf("\tyes 2\n");
+#endif
+	    return 1;
+	}
+	if (!cd && getModule() == smember->getModule())
+	{
+#if LOG
+	    printf("\tyes 3\n");
+#endif
+	    return 1;
+	}
+    }
+#if LOG
+    printf("\tno\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ */
+
+void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+#if 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());
+    }
+#endif
+    if (!e)
+    {
+	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
+	    d->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 == Tclass)
+    {   // Do access check
+	ClassDeclaration *cd;
+
+	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+#if 1
+	if (e->op == TOKsuper)
+	{   ClassDeclaration *cd2;
+
+	    cd2 = sc->func->toParent()->isClassDeclaration();
+	    if (cd2)
+		cd = cd2;
+	}
+#endif
+	cd->accessCheck(loc, sc, d);
+    }
+    else if (e->type->ty == Tstruct)
+    {   // Do access check
+	StructDeclaration *cd;
+
+	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+	cd->accessCheck(loc, sc, d);
+    }
+}
--- a/dmd/aggregate.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/aggregate.h	Sat Jul 12 19:38:31 2008 +0200
@@ -64,14 +64,15 @@
 				// 2: cannot determine size; fwd referenced
     int isdeprecated;		// !=0 if deprecated
     Scope *scope;		// !=NULL means context to use
-    FuncDeclarations dtors;	// Array of destructors
-    FuncDeclaration *dtor;	// aggregate destructor
 
     // Special member functions
     InvariantDeclaration *inv;		// invariant
     NewDeclaration *aggNew;		// allocator
     DeleteDeclaration *aggDelete;	// deallocator
 
+    FuncDeclarations dtors;	// Array of destructors
+    FuncDeclaration *dtor;	// aggregate destructor
+
 #ifdef IN_GCC
     Array methods;              // flat list of all methods for debug information
 #endif
@@ -119,19 +120,26 @@
 struct StructDeclaration : AggregateDeclaration
 {
     int zeroInit;		// !=0 if initialize with 0 fill
+#if 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
+#endif
 
     StructDeclaration(Loc loc, Identifier *id);
     Dsymbol *syntaxCopy(Dsymbol *s);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     char *mangle();
-    char *kind();
+    const char *kind();
     Expression *cloneMembers();
     void toDocBuffer(OutBuffer *buf);
 
     PROT getAccess(Dsymbol *smember);	// determine access to smember
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     void toDt(dt_t **pdt);
     void toDebug();			// to symbolic debug info
 
@@ -142,7 +150,7 @@
 {
     UnionDeclaration(Loc loc, Identifier *id);
     Dsymbol *syntaxCopy(Dsymbol *s);
-    char *kind();
+    const char *kind();
 
     UnionDeclaration *isUnionDeclaration() { return this; }
 };
@@ -168,7 +176,7 @@
     void copyBaseInterfaces(BaseClasses *);
 };
 
-#if V2
+#if DMDV2
 #define CLASSINFO_SIZE 	(0x3C+16)	// value of ClassInfo.size
 #else
 #define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
@@ -218,7 +226,7 @@
     virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
 
     Dsymbol *search(Loc, Identifier *ident, int flags);
-#if V2
+#if DMDV2
     int isFuncHidden(FuncDeclaration *fd);
 #endif
     FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
@@ -226,12 +234,12 @@
     int isNested();
     int isCOMclass();
     virtual int isCOMinterface();
-#if V2
+#if DMDV2
     virtual int isCPPinterface();
 #endif
     int isAbstract();
     virtual int vtblOffset();
-    char *kind();
+    const char *kind();
     char *mangle();
     void toDocBuffer(OutBuffer *buf);
 
@@ -240,7 +248,7 @@
     void addLocalClass(ClassDeclarations *);
 
     // Back end
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     void toDebug();
     unsigned baseVtblOffset(BaseClass *bc);
     Symbol *toSymbol();
@@ -258,7 +266,7 @@
 
 struct InterfaceDeclaration : ClassDeclaration
 {
-#if V2
+#if DMDV2
     int cpp;				// !=0 if this is a C++ interface
 #endif
     InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
@@ -266,14 +274,14 @@
     void semantic(Scope *sc);
     int isBaseOf(ClassDeclaration *cd, int *poffset);
     int isBaseOf(BaseClass *bc, int *poffset);
-    char *kind();
+    const char *kind();
     int vtblOffset();
-#if V2
+#if DMDV2
     int isCPPinterface();
 #endif
     virtual int isCOMinterface();
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     Symbol *toSymbol();
 
     InterfaceDeclaration *isInterfaceDeclaration() { return this; }
--- a/dmd/attrib.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/attrib.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -35,6 +35,7 @@
 #include "../gen/logger.h"
 
 extern void obj_includelib(char *name);
+void obj_startaddress(Symbol *s);
 
 
 /********************************* AttribDeclaration ****************************/
@@ -52,16 +53,13 @@
 
 int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
 {
-    unsigned i;
     int m = 0;
     Array *d = include(sc, sd);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    m |= s->addMember(sc, sd, m | memnum);
 	}
     }
@@ -72,7 +70,7 @@
 {
     Array *d = include(sc, NULL);
 
-    //printf("\tAttribDeclaration::semantic '%s'\n",toChars());
+    //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
     if (d)
     {
 	for (unsigned i = 0; i < d->dim; i++)
@@ -86,15 +84,12 @@
 
 void AttribDeclaration::semantic2(Scope *sc)
 {
-    unsigned i;
     Array *d = include(sc, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    s->semantic2(sc);
 	}
     }
@@ -102,15 +97,12 @@
 
 void AttribDeclaration::semantic3(Scope *sc)
 {
-    unsigned i;
     Array *d = include(sc, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    s->semantic3(sc);
 	}
     }
@@ -118,15 +110,12 @@
 
 void AttribDeclaration::inlineScan()
 {
-    unsigned i;
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
 	    s->inlineScan();
 	}
@@ -137,15 +126,12 @@
 {
     if (comment)
     {
-	unsigned i;
 	Array *d = include(NULL, NULL);
 
 	if (d)
 	{
-	    for (i = 0; i < d->dim; i++)
-	    {   Dsymbol *s;
-
-		s = (Dsymbol *)d->data[i];
+	    for (unsigned i = 0; i < d->dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)d->data[i];
 		//printf("AttribDeclaration::addComment %s\n", s->toChars());
 		s->addComment(comment);
 	    }
@@ -163,50 +149,41 @@
 //    if (sc->docbuf)
 //	return;
 
-    unsigned i;
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
 	    s->emitComment(sc);
 	}
     }
 }
 
-void AttribDeclaration::toObjFile()
+void AttribDeclaration::toObjFile(int multiobj)
 {
-    unsigned i;
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
-	    s->toObjFile();
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->toObjFile(multiobj);
 	}
     }
 }
 
 int AttribDeclaration::cvMember(unsigned char *p)
 {
-    unsigned i;
     int nwritten = 0;
     int n;
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    n = s->cvMember(p);
 	    if (p)
 		p += n;
@@ -232,7 +209,7 @@
     return 0;
 }
 
-char *AttribDeclaration::kind()
+const char *AttribDeclaration::kind()
 {
     return "attribute";
 }
@@ -246,15 +223,12 @@
 
 void AttribDeclaration::checkCtorConstInit()
 {
-    unsigned i;
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    s->checkCtorConstInit();
 	}
     }
@@ -264,15 +238,13 @@
  */
 
 void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
-{   unsigned i;
+{
     Array *d = include(NULL, NULL);
 
     if (d)
     {
-	for (i = 0; i < d->dim; i++)
-	{   Dsymbol *s;
-
-	    s = (Dsymbol *)d->data[i];
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
 	    s->addLocalClass(aclasses);
 	}
     }
@@ -723,7 +695,7 @@
     buf->writestring("}\n");
 }
 
-char *AnonDeclaration::kind()
+const char *AnonDeclaration::kind()
 {
     return (char *)(isunion ? "anonymous union" : "anonymous struct");
 }
@@ -1023,12 +995,12 @@
     return TRUE;
 }
 
-char *PragmaDeclaration::kind()
+const char *PragmaDeclaration::kind()
 {
     return "pragma";
 }
 
-void PragmaDeclaration::toObjFile()
+void PragmaDeclaration::toObjFile(int multiobj)
 {
     if (ident == Id::lib)
     {
@@ -1044,7 +1016,7 @@
 	name[se->len] = 0;
 	obj_includelib(name);
     }
-    AttribDeclaration::toObjFile();
+    AttribDeclaration::toObjFile(multiobj);
 }
 
 void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
@@ -1214,6 +1186,7 @@
 
 int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
 {
+    //printf("StaticIfDeclaration::addMember() '%s'\n",toChars());
     /* This is deferred until semantic(), so that
      * expressions in the condition can refer to declarations
      * in the same scope, such as:
@@ -1240,7 +1213,7 @@
 {
     Array *d = include(sc, sd);
 
-    //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars());
+    //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d);
     if (d)
     {
 	if (!addisdone)
@@ -1257,7 +1230,7 @@
     }
 }
 
-char *StaticIfDeclaration::kind()
+const char *StaticIfDeclaration::kind()
 {
     return "static if";
 }
@@ -1268,8 +1241,10 @@
 CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
     : AttribDeclaration(NULL)
 {
+    this->loc = loc;
     this->exp = exp;
     this->sd = NULL;
+    this->compiled = 0;
 }
 
 Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
@@ -1281,32 +1256,50 @@
 
 int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
 {
+    //printf("CompileDeclaration::addMember(sc = %p)\n", sc);
     this->sd = sd;
+    if (memnum == 0)
+    {	/* No members yet, so parse the mixin now
+	 */
+	compileIt(sc);
+	memnum |= AttribDeclaration::addMember(sc, sd, memnum);
+	compiled = 1;
+    }
     return memnum;
 }
 
+void CompileDeclaration::compileIt(Scope *sc)
+{
+    //printf("CompileDeclaration::compileIt()\n");
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    if (exp->op != TOKstring)
+    {	exp->error("argument to mixin must be a string, not (%s)", exp->toChars());
+    }
+    else
+    {
+	StringExp *se = (StringExp *)exp;
+	se = se->toUTF8(sc);
+	Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+	p.loc = loc;
+	p.nextToken();
+	decl = p.parseDeclDefs(0);
+	if (p.token.value != TOKeof)
+	    exp->error("incomplete mixin declaration (%s)", se->toChars());
+    }
+}
+
 void CompileDeclaration::semantic(Scope *sc)
 {
     //printf("CompileDeclaration::semantic()\n");
-    exp = exp->semantic(sc);
-    exp = resolveProperties(sc, exp);
-    exp = exp->optimize(WANTvalue | WANTinterpret);
-    if (exp->op != TOKstring)
-    {	error("argument to mixin must be a string, not (%s)", exp->toChars());
-	return;
+
+    if (!compiled)
+    {
+	compileIt(sc);
+	AttribDeclaration::addMember(sc, sd, 0);
+	compiled = 1;
     }
-    StringExp *se = (StringExp *)exp;
-    se = se->toUTF8(sc);
-    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
-    p.loc = loc;
-    p.nextToken();
-    decl = p.parseDeclDefs(0);
-    if (p.token.value != TOKeof)
-    {
-	error("incomplete mixin declaration (%s)", se->toChars());
-    }
-
-    AttribDeclaration::addMember(sc, sd, 0);
     AttribDeclaration::semantic(sc);
 }
 
--- a/dmd/attrib.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/attrib.h	Sat Jul 12 19:38:31 2008 +0200
@@ -42,7 +42,7 @@
     void inlineScan();
     void addComment(unsigned char *comment);
     void emitComment(Scope *sc);
-    char *kind();
+    const char *kind();
     int oneMember(Dsymbol **ps);
     int hasPointers();
     void checkCtorConstInit();
@@ -50,7 +50,7 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     AttribDeclaration *isAttribDeclaration() { return this; }
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     int cvMember(unsigned char *p);
 };
 
@@ -106,7 +106,7 @@
     Dsymbol *syntaxCopy(Dsymbol *s);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
 };
 
 struct PragmaDeclaration : AttribDeclaration
@@ -118,8 +118,8 @@
     void semantic(Scope *sc);
     int oneMember(Dsymbol **ps);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
-    void toObjFile();			// compile to .obj file
+    const char *kind();
+    void toObjFile(int multiobj);			// compile to .obj file
 };
 
 struct ConditionalDeclaration : AttribDeclaration
@@ -145,7 +145,7 @@
     Dsymbol *syntaxCopy(Dsymbol *s);
     int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
     void semantic(Scope *sc);
-    char *kind();
+    const char *kind();
 };
 
 // Mixin declarations
@@ -155,10 +155,12 @@
     Expression *exp;
 
     ScopeDsymbol *sd;
+    int compiled;
 
     CompileDeclaration(Loc loc, Expression *exp);
     Dsymbol *syntaxCopy(Dsymbol *s);
     int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
+    void compileIt(Scope *sc);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 };
--- a/dmd/cast.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/cast.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,5 +1,5 @@
 
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -1345,31 +1345,52 @@
 	goto Lt1;
     }
     else if (t1->ty == Tclass || t2->ty == Tclass)
-    {	int i1;
-	int i2;
-
-	i1 = e2->implicitConvTo(t1);
-	i2 = e1->implicitConvTo(t2);
-
-	if (i1 && i2)
+    {
+	while (1)
 	{
-	    // We have the case of class vs. void*, so pick class
-	    if (t1->ty == Tpointer)
-		i1 = 0;
-	    else if (t2->ty == Tpointer)
-		i2 = 0;
-	}
+	    int i1 = e2->implicitConvTo(t1);
+	    int i2 = e1->implicitConvTo(t2);
+
+	    if (i1 && i2)
+	    {
+		// We have the case of class vs. void*, so pick class
+		if (t1->ty == Tpointer)
+		    i1 = 0;
+		else if (t2->ty == Tpointer)
+		    i2 = 0;
+	    }
 
-	if (i2)
-	{
-	    goto Lt2;
+	    if (i2)
+	    {
+		goto Lt2;
+	    }
+	    else if (i1)
+	    {
+		goto Lt1;
+	    }
+	    else if (t1->ty == Tclass && t2->ty == Tclass)
+	    {	TypeClass *tc1 = (TypeClass *)t1;
+		TypeClass *tc2 = (TypeClass *)t2;
+
+		/* Pick 'tightest' type
+		 */
+		ClassDeclaration *cd1 = tc1->sym->baseClass;
+		ClassDeclaration *cd2 = tc1->sym->baseClass;
+
+		if (cd1 && cd2)
+		{   t1 = cd1->type;
+		    t2 = cd2->type;
+		}
+		else if (cd1)
+		    t1 = cd1->type;
+		else if (cd2)
+		    t2 = cd2->type;
+		else
+		    goto Lincompatible;
+	    }
+	    else
+		goto Lincompatible;
 	}
-	else if (i1)
-	{
-	    goto Lt1;
-	}
-	else
-	    goto Lincompatible;
     }
     else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
     {
--- a/dmd/class.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/class.c	Sat Jul 12 19:38:31 2008 +0200
@@ -147,7 +147,7 @@
 		Type::typeinfotypelist = this;
 	    }
 
-#if V2
+#if DMDV2
 	    if (id == Id::TypeInfo_Const)
 	    {	if (Type::typeinfoconst)
 		    Type::typeinfoconst->error("%s", msg);
@@ -261,7 +261,7 @@
 #endif
 
     if (sc->stc & STCdeprecated)
-    {	//printf("test1: %s is deprecated\n", toChars());
+    {
 	isdeprecated = 1;
     }
 
@@ -302,6 +302,7 @@
 	else
 	{
 	    tc = (TypeClass *)(tb);
+
 	    if (tc->sym->isDeprecated())
 	    {
 		if (!isDeprecated())
@@ -565,7 +566,7 @@
 	scope->setNoFree();
 	scope->module->addDeferredSemantic(this);
 
-	//printf("\tsemantic('%s') failed\n", toChars());
+	//printf("\tsemantic('%s') failed due to forward references\n", toChars());
 	return;
     }
 
@@ -599,7 +600,7 @@
     if (!ctor && baseClass && baseClass->ctor)
     {
 	//printf("Creating default this(){} for class %s\n", toChars());
-	ctor = new CtorDeclaration(0, 0, NULL, 0);
+	ctor = new CtorDeclaration(loc, 0, NULL, 0);
 	ctor->fbody = new CompoundStatement(0, new Statements());
 	members->push(ctor);
 	ctor->addMember(sc, this, 1);
@@ -796,7 +797,7 @@
  * Return 1 if function is hidden (not findable through search).
  */
 
-#if V2
+#if DMDV2
 int isf(void *param, FuncDeclaration *fd)
 {
     //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
@@ -857,12 +858,11 @@
 }
 
 void ClassDeclaration::interfaceSemantic(Scope *sc)
-{   int i;
-
+{
     vtblInterfaces = new BaseClasses();
     vtblInterfaces->reserve(interfaces_dim);
 
-    for (i = 0; i < interfaces_dim; i++)
+    for (size_t i = 0; i < interfaces_dim; i++)
     {
 	BaseClass *b = interfaces[i];
 
@@ -911,6 +911,7 @@
     return FALSE;
 }
 
+
 /****************************************
  * Returns !=0 if there's an extra member which is the 'this'
  * pointer to the enclosing context (enclosing class or function)
@@ -936,7 +937,7 @@
 /****************************************
  */
 
-char *ClassDeclaration::kind()
+const char *ClassDeclaration::kind()
 {
     return "class";
 }
@@ -1234,7 +1235,7 @@
 /*******************************************
  */
 
-char *InterfaceDeclaration::kind()
+const char *InterfaceDeclaration::kind()
 {
     return "interface";
 }
--- a/dmd/clone.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/clone.c	Sat Jul 12 19:38:31 2008 +0200
@@ -28,7 +28,7 @@
  * (can be NULL for members that don't need one)
  */
 
-#if V2
+#if DMDV2
 Expression *StructDeclaration::cloneMembers()
 {
     Expression *e = NULL;
@@ -89,7 +89,7 @@
     //printf("StructDeclaration::buildDtor() %s\n", toChars());
     Expression *e = NULL;
 
-#if V2
+#if DMDV2
     for (size_t i = 0; i < fields.dim; i++)
     {
 	Dsymbol *s = (Dsymbol *)fields.data[i];
--- a/dmd/constfold.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/constfold.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,1506 +1,1512 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <math.h>
-
-#if __DMC__
-#include <complex.h>
-#endif
-
-#include "mem.h"
-#include "root.h"
-
-#include "mtype.h"
-#include "expression.h"
-#include "aggregate.h"
-#include "declaration.h"
-
-#ifdef IN_GCC
-#include "d-gcc-real.h"
-
-/* %% fix? */
-extern "C" bool real_isnan (const real_t *);
-#endif
-
-static real_t zero;	// work around DMC bug for now
-
-#define LOG 0
-
-Expression *expType(Type *type, Expression *e)
-{
-    if (type != e->type)
-    {
-	e = e->copy();
-	e->type = type;
-    }
-    return e;
-}
-
-/* ================================== isConst() ============================== */
-
-int Expression::isConst()
-{
-    //printf("Expression::isConst(): %s\n", toChars());
-    return 0;
-}
-
-int IntegerExp::isConst()
-{
-    return 1;
-}
-
-int RealExp::isConst()
-{
-    return 1;
-}
-
-int ComplexExp::isConst()
-{
-    return 1;
-}
-
-int SymOffExp::isConst()
-{
-    return 2;
-}
-
-/* =============================== constFold() ============================== */
-
-/* The constFold() functions were redundant with the optimize() ones,
- * and so have been folded in with them.
- */
-
-/* ========================================================================== */
-
-Expression *Neg(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (e1->type->isreal())
-    {
-	e = new RealExp(loc, -e1->toReal(), type);
-    }
-    else if (e1->type->isimaginary())
-    {
-	e = new RealExp(loc, -e1->toImaginary(), type);
-    }
-    else if (e1->type->iscomplex())
-    {
-	e = new ComplexExp(loc, -e1->toComplex(), type);
-    }
-    else
-	e = new IntegerExp(loc, -e1->toInteger(), type);
-    return e;
-}
-
-Expression *Com(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, ~e1->toInteger(), type);
-    return e;
-}
-
-Expression *Not(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->isBool(0), type);
-    return e;
-}
-
-Expression *Bool(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->isBool(1), type);
-    return e;
-}
-
-Expression *Add(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-#if LOG
-    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-#endif
-    if (type->isreal())
-    {
-	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
-    }
-    else if (type->isimaginary())
-    {
-	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
-    }
-    else if (type->iscomplex())
-    {
-	// This rigamarole is necessary so that -0.0 doesn't get
-	// converted to +0.0 by doing an extraneous add with +0.0
-	complex_t c1;
-	real_t r1;
-	real_t i1;
-
-	complex_t c2;
-	real_t r2;
-	real_t i2;
-
-	complex_t v;
-	int x;
-
-	if (e1->type->isreal())
-	{   r1 = e1->toReal();
-	    x = 0;
-	}
-	else if (e1->type->isimaginary())
-	{   i1 = e1->toImaginary();
-	    x = 3;
-	}
-	else
-	{   c1 = e1->toComplex();
-	    x = 6;
-	}
-
-	if (e2->type->isreal())
-	{   r2 = e2->toReal();
-	}
-	else if (e2->type->isimaginary())
-	{   i2 = e2->toImaginary();
-	    x += 1;
-	}
-	else
-	{   c2 = e2->toComplex();
-	    x += 2;
-	}
-
-	switch (x)
-	{
-#if __DMC__
-	    case 0+0:	v = (complex_t) (r1 + r2);	break;
-	    case 0+1:	v = r1 + i2 * I;		break;
-	    case 0+2:	v = r1 + c2;			break;
-	    case 3+0:	v = i1 * I + r2;		break;
-	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
-	    case 3+2:	v = i1 * I + c2;		break;
-	    case 6+0:	v = c1 + r2;			break;
-	    case 6+1:	v = c1 + i2 * I;		break;
-	    case 6+2:	v = c1 + c2;			break;
-#else
-	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
-	    case 0+1:	v = complex_t(r1, i2);		break;
-	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
-	    case 3+0:	v = complex_t(r2, i1);		break;
-	    case 3+1:	v = complex_t(0, i1 + i2);	break;
-	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
-	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
-	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
-	    case 6+2:	v = c1 + c2;			break;
-#endif
-	    default: assert(0);
-	}
-	e = new ComplexExp(loc, v, type);
-    }
-    else if (e1->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e1;
-	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
-	e->type = type;
-    }
-    else if (e2->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e2;
-	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
-	e->type = type;
-    }
-    else
-	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
-    return e;
-}
-
-
-Expression *Min(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isreal())
-    {
-	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
-    }
-    else if (type->isimaginary())
-    {
-	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
-    }
-    else if (type->iscomplex())
-    {
-	// This rigamarole is necessary so that -0.0 doesn't get
-	// converted to +0.0 by doing an extraneous add with +0.0
-	complex_t c1;
-	real_t r1;
-	real_t i1;
-
-	complex_t c2;
-	real_t r2;
-	real_t i2;
-
-	complex_t v;
-	int x;
-
-	if (e1->type->isreal())
-	{   r1 = e1->toReal();
-	    x = 0;
-	}
-	else if (e1->type->isimaginary())
-	{   i1 = e1->toImaginary();
-	    x = 3;
-	}
-	else
-	{   c1 = e1->toComplex();
-	    x = 6;
-	}
-
-	if (e2->type->isreal())
-	{   r2 = e2->toReal();
-	}
-	else if (e2->type->isimaginary())
-	{   i2 = e2->toImaginary();
-	    x += 1;
-	}
-	else
-	{   c2 = e2->toComplex();
-	    x += 2;
-	}
-
-	switch (x)
-	{
-#if __DMC__
-	    case 0+0:	v = (complex_t) (r1 - r2);	break;
-	    case 0+1:	v = r1 - i2 * I;		break;
-	    case 0+2:	v = r1 - c2;			break;
-	    case 3+0:	v = i1 * I - r2;		break;
-	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
-	    case 3+2:	v = i1 * I - c2;		break;
-	    case 6+0:	v = c1 - r2;			break;
-	    case 6+1:	v = c1 - i2 * I;		break;
-	    case 6+2:	v = c1 - c2;			break;
-#else
-	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
-	    case 0+1:	v = complex_t(r1, -i2);		break;
-	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
-	    case 3+0:	v = complex_t(-r2, i1);		break;
-	    case 3+1:	v = complex_t(0, i1 - i2);	break;
-	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
-	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
-	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
-	    case 6+2:	v = c1 - c2;			break;
-#endif
-	    default: assert(0);
-	}
-	e = new ComplexExp(loc, v, type);
-    }
-    else if (e1->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e1;
-	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
-	e->type = type;
-    }
-    else
-    {
-	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
-    }
-    return e;
-}
-
-Expression *Mul(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {   complex_t c;
-#ifdef IN_GCC
-	real_t r;
-#else
-	d_float80 r;
-#endif
-
-	if (e1->type->isreal())
-	{
-#if __DMC__
-	    c = e1->toReal() * e2->toComplex();
-#else
-	    r = e1->toReal();
-	    c = e2->toComplex();
-	    c = complex_t(r * creall(c), r * cimagl(c));
-#endif
-	}
-	else if (e1->type->isimaginary())
-	{
-#if __DMC__
-	    c = e1->toImaginary() * I * e2->toComplex();
-#else
-	    r = e1->toImaginary();
-	    c = e2->toComplex();
-	    c = complex_t(-r * cimagl(c), r * creall(c));
-#endif
-	}
-	else if (e2->type->isreal())
-	{
-#if __DMC__
-	    c = e2->toReal() * e1->toComplex();
-#else
-	    r = e2->toReal();
-	    c = e1->toComplex();
-	    c = complex_t(r * creall(c), r * cimagl(c));
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{
-#if __DMC__
-	    c = e1->toComplex() * e2->toImaginary() * I;
-#else
-	    r = e2->toImaginary();
-	    c = e1->toComplex();
-	    c = complex_t(-r * cimagl(c), r * creall(c));
-#endif
-	}
-	else
-	    c = e1->toComplex() * e2->toComplex();
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {
-	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
-    }
-    return e;
-}
-
-Expression *Div(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {   complex_t c;
-#ifdef IN_GCC
-	real_t r;
-#else
-	d_float80 r;
-#endif
-
-	//e1->type->print();
-	//e2->type->print();
-	if (e2->type->isreal())
-	{
-	    if (e1->type->isreal())
-	    {
-		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
-		return e;
-	    }
-#if __DMC__
-	    //r = e2->toReal();
-	    //c = e1->toComplex();
-	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
-
-	    c = e1->toComplex() / e2->toReal();
-#else
-	    r = e2->toReal();
-	    c = e1->toComplex();
-	    c = complex_t(creall(c) / r, cimagl(c) / r);
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{
-#if __DMC__
-	    //r = e2->toImaginary();
-	    //c = e1->toComplex();
-	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
-
-	    c = e1->toComplex() / (e2->toImaginary() * I);
-#else
-	    r = e2->toImaginary();
-	    c = e1->toComplex();
-	    c = complex_t(cimagl(c) / r, -creall(c) / r);
-#endif
-	}
-	else
-	{
-	    c = e1->toComplex() / e2->toComplex();
-	}
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-	sinteger_t n;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (n2 == 0)
-	{   e2->error("divide by 0");
-	    e2 = new IntegerExp(0, 1, e2->type);
-	    n2 = 1;
-	}
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	    n = ((d_uns64) n1) / ((d_uns64) n2);
-	else
-	    n = n1 / n2;
-	e = new IntegerExp(loc, n, type);
-    }
-    return e;
-}
-
-Expression *Mod(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {
-	complex_t c;
-
-	if (e2->type->isreal())
-	{   real_t r2 = e2->toReal();
-
-#ifdef __DMC__
-	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
-#elif defined(IN_GCC)
-	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
-#else
-	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{   real_t i2 = e2->toImaginary();
-
-#ifdef __DMC__
-	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
-#elif defined(IN_GCC)
-	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
-#else
-	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
-#endif
-	}
-	else
-	    assert(0);
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-	sinteger_t n;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (n2 == 0)
-	{   e2->error("divide by 0");
-	    e2 = new IntegerExp(0, 1, e2->type);
-	    n2 = 1;
-	}
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	    n = ((d_uns64) n1) % ((d_uns64) n2);
-	else
-	    n = n1 % n2;
-	e = new IntegerExp(loc, n, type);
-    }
-    return e;
-}
-
-Expression *Shl(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
-    return e;
-}
-
-Expression *Shr(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    unsigned count;
-    integer_t value;
-
-    value = e1->toInteger();
-    count = e2->toInteger();
-    switch (e1->type->toBasetype()->ty)
-    {
-	case Tint8:
-		value = (d_int8)(value) >> count;
-		break;
-
-	case Tuns8:
-		value = (d_uns8)(value) >> count;
-		break;
-
-	case Tint16:
-		value = (d_int16)(value) >> count;
-		break;
-
-	case Tuns16:
-		value = (d_uns16)(value) >> count;
-		break;
-
-	case Tint32:
-		value = (d_int32)(value) >> count;
-		break;
-
-	case Tuns32:
-		value = (d_uns32)(value) >> count;
-		break;
-
-	case Tint64:
-		value = (d_int64)(value) >> count;
-		break;
-
-	case Tuns64:
-		value = (d_uns64)(value) >> count;
-		break;
-
-	default:
-		assert(0);
-    }
-    e = new IntegerExp(loc, value, type);
-    return e;
-}
-
-Expression *Ushr(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    unsigned count;
-    integer_t value;
-
-    value = e1->toInteger();
-    count = e2->toInteger();
-    switch (e1->type->toBasetype()->ty)
-    {
-	case Tint8:
-	case Tuns8:
-		assert(0);		// no way to trigger this
-		value = (value & 0xFF) >> count;
-		break;
-
-	case Tint16:
-	case Tuns16:
-		assert(0);		// no way to trigger this
-		value = (value & 0xFFFF) >> count;
-		break;
-
-	case Tint32:
-	case Tuns32:
-		value = (value & 0xFFFFFFFF) >> count;
-		break;
-
-	case Tint64:
-	case Tuns64:
-		value = (d_uns64)(value) >> count;
-		break;
-
-	default:
-		assert(0);
-    }
-    e = new IntegerExp(loc, value, type);
-    return e;
-}
-
-Expression *And(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
-    return e;
-}
-
-Expression *Or(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
-    return e;
-}
-
-Expression *Xor(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
-    return e;
-}
-
-/* Also returns EXP_CANT_INTERPRET if cannot be computed.
- */
-Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    int cmp;
-    real_t r1;
-    real_t r2;
-
-    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
-    assert(op == TOKequal || op == TOKnotequal);
-
-    if (e1->op == TOKnull)
-    {
-	if (e2->op == TOKnull)
-	    cmp = 1;
-	else if (e2->op == TOKstring)
-	{   StringExp *es2 = (StringExp *)e2;
-	    cmp = (0 == es2->len);
-	}
-	else if (e2->op == TOKarrayliteral)
-	{   ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-	    cmp = !es2->elements || (0 == es2->elements->dim);
-	}
-	else
-	    return EXP_CANT_INTERPRET;
-    }
-    else if (e2->op == TOKnull)
-    {
-	if (e1->op == TOKstring)
-	{   StringExp *es1 = (StringExp *)e1;
-	    cmp = (0 == es1->len);
-	}
-	else if (e1->op == TOKarrayliteral)
-	{   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	    cmp = !es1->elements || (0 == es1->elements->dim);
-	}
-	else
-	    return EXP_CANT_INTERPRET;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKstring)
-    {	StringExp *es1 = (StringExp *)e1;
-	StringExp *es2 = (StringExp *)e2;
-
-	assert(es1->sz == es2->sz);
-	if (es1->len == es2->len &&
-	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
-	    cmp = 1;
-	else
-	    cmp = 0;
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
-    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	if ((!es1->elements || !es1->elements->dim) &&
-	    (!es2->elements || !es2->elements->dim))
-	    cmp = 1;		// both arrays are empty
-	else if (!es1->elements || !es2->elements)
-	    cmp = 0;
-	else if (es1->elements->dim != es2->elements->dim)
-	    cmp = 0;
-	else
-	{
-	    for (size_t i = 0; i < es1->elements->dim; i++)
-	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-
-		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
-		if (v == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
-		cmp = v->toInteger();
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
-    {	// Swap operands and use common code
-	Expression *e = e1;
-	e1 = e2;
-	e2 = e;
-	goto Lsa;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
-    {
-     Lsa:
-	StringExp *es1 = (StringExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-	size_t dim1 = es1->len;
-	size_t dim2 = es2->elements ? es2->elements->dim : 0;
-	if (dim1 != dim2)
-	    cmp = 0;
-	else
-	{
-	    for (size_t i = 0; i < dim1; i++)
-	    {
-		uinteger_t c = es1->charAt(i);
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-		if (ee2->isConst() != 1)
-		    return EXP_CANT_INTERPRET;
-		cmp = (c == ee2->toInteger());
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
-    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
-	StructLiteralExp *es2 = (StructLiteralExp *)e2;
-
-	if (es1->sd != es2->sd)
-	    cmp = 0;
-	else if ((!es1->elements || !es1->elements->dim) &&
-	    (!es2->elements || !es2->elements->dim))
-	    cmp = 1;		// both arrays are empty
-	else if (!es1->elements || !es2->elements)
-	    cmp = 0;
-	else if (es1->elements->dim != es2->elements->dim)
-	    cmp = 0;
-	else
-	{
-	    cmp = 1;
-	    for (size_t i = 0; i < es1->elements->dim; i++)
-	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-
-		if (ee1 == ee2)
-		    continue;
-		if (!ee1 || !ee2)
-		{   cmp = 0;
-		    break;
-		}
-		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
-		if (v == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
-		cmp = v->toInteger();
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-#if 0 // Should handle this
-    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
-    {
-    }
-#endif
-    else if (e1->isConst() != 1 || e2->isConst() != 1)
-	return EXP_CANT_INTERPRET;
-    else if (e1->type->isreal())
-    {
-	r1 = e1->toReal();
-	r2 = e2->toReal();
-	goto L1;
-    }
-    else if (e1->type->isimaginary())
-    {
-	r1 = e1->toImaginary();
-	r2 = e2->toImaginary();
-     L1:
-#if __DMC__
-	cmp = (r1 == r2);
-#else
-	if (isnan(r1) || isnan(r2))	// if unordered
-	{
-	    cmp = 0;
-	}
-	else
-	{
-	    cmp = (r1 == r2);
-	}
-#endif
-    }
-    else if (e1->type->iscomplex())
-    {
-	cmp = e1->toComplex() == e2->toComplex();
-    }
-    else if (e1->type->isintegral())
-    {
-	cmp = (e1->toInteger() == e2->toInteger());
-    }
-    else
-	return EXP_CANT_INTERPRET;
-    if (op == TOKnotequal)
-	cmp ^= 1;
-    e = new IntegerExp(loc, cmp, type);
-    return e;
-}
-
-Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    int cmp;
-
-    if (e1->op == TOKnull && e2->op == TOKnull)
-    {
-	cmp = 1;
-    }
-    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
-    {
-	SymOffExp *es1 = (SymOffExp *)e1;
-	SymOffExp *es2 = (SymOffExp *)e2;
-
-	cmp = (es1->var == es2->var && es1->offset == es2->offset);
-    }
-    else if (e1->isConst() == 1 && e2->isConst() == 1)
-	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
-		type, e1, e2);
-    else
-	assert(0);
-    if (op == TOKnotidentity)
-	cmp ^= 1;
-    return new IntegerExp(loc, cmp, type);
-}
-
-
-Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    integer_t n;
-    real_t r1;
-    real_t r2;
-
-    if (e1->type->isreal())
-    {
-	r1 = e1->toReal();
-	r2 = e2->toReal();
-	goto L1;
-    }
-    else if (e1->type->isimaginary())
-    {
-	r1 = e1->toImaginary();
-	r2 = e2->toImaginary();
-     L1:
-#if __DMC__
-	// DMC is the only compiler I know of that handles NAN arguments
-	// correctly in comparisons.
-	switch (op)
-	{
-	    case TOKlt:	   n = r1 <  r2;	break;
-	    case TOKle:	   n = r1 <= r2;	break;
-	    case TOKgt:	   n = r1 >  r2;	break;
-	    case TOKge:	   n = r1 >= r2;	break;
-
-	    case TOKleg:   n = r1 <>=  r2;	break;
-	    case TOKlg:	   n = r1 <>   r2;	break;
-	    case TOKunord: n = r1 !<>= r2;	break;
-	    case TOKue:	   n = r1 !<>  r2;	break;
-	    case TOKug:	   n = r1 !<=  r2;	break;
-	    case TOKuge:   n = r1 !<   r2;	break;
-	    case TOKul:	   n = r1 !>=  r2;	break;
-	    case TOKule:   n = r1 !>   r2;	break;
-
-	    default:
-		assert(0);
-	}
-#else
-	// Don't rely on compiler, handle NAN arguments separately
-#if IN_GCC
-	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
-#else
-	if (isnan(r1) || isnan(r2))	// if unordered
-#endif
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = 0;	break;
-		case TOKle:	n = 0;	break;
-		case TOKgt:	n = 0;	break;
-		case TOKge:	n = 0;	break;
-
-		case TOKleg:	n = 0;	break;
-		case TOKlg:	n = 0;	break;
-		case TOKunord:	n = 1;	break;
-		case TOKue:	n = 1;	break;
-		case TOKug:	n = 1;	break;
-		case TOKuge:	n = 1;	break;
-		case TOKul:	n = 1;	break;
-		case TOKule:	n = 1;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-	else
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = r1 <  r2;	break;
-		case TOKle:	n = r1 <= r2;	break;
-		case TOKgt:	n = r1 >  r2;	break;
-		case TOKge:	n = r1 >= r2;	break;
-
-		case TOKleg:	n = 1;		break;
-		case TOKlg:	n = r1 != r2;	break;
-		case TOKunord:	n = 0;		break;
-		case TOKue:	n = r1 == r2;	break;
-		case TOKug:	n = r1 >  r2;	break;
-		case TOKuge:	n = r1 >= r2;	break;
-		case TOKul:	n = r1 <  r2;	break;
-		case TOKule:	n = r1 <= r2;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-#endif
-    }
-    else if (e1->type->iscomplex())
-    {
-	assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
-		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
-		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
-		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
-
-		case TOKleg:	n = 1;					break;
-		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
-		case TOKunord:	n = 0;					break;
-		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
-		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
-		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
-		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
-		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-	else
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = n1 <  n2;	break;
-		case TOKle:	n = n1 <= n2;	break;
-		case TOKgt:	n = n1 >  n2;	break;
-		case TOKge:	n = n1 >= n2;	break;
-
-		case TOKleg:	n = 1;		break;
-		case TOKlg:	n = n1 != n2;	break;
-		case TOKunord:	n = 0;		break;
-		case TOKue:	n = n1 == n2;	break;
-		case TOKug:	n = n1 >  n2;	break;
-		case TOKuge:	n = n1 >= n2;	break;
-		case TOKul:	n = n1 <  n2;	break;
-		case TOKule:	n = n1 <= n2;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-    }
-    e = new IntegerExp(loc, n, type);
-    return e;
-}
-
-/* Also returns EXP_CANT_INTERPRET if cannot be computed.
- *  to:	type to cast to
- *  type: type to paint the result
- */
-
-Expression *Cast(Type *type, Type *to, Expression *e1)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
-    //printf("e1->type = %s\n", e1->type->toChars());
-    if (type->equals(e1->type) && to->equals(type))
-	return e1;
-
-    if (e1->isConst() != 1)
-	return EXP_CANT_INTERPRET;
-
-    Type *tb = to->toBasetype();
-    if (tb->ty == Tbool)
-	e = new IntegerExp(loc, e1->toInteger() != 0, type);
-    else if (type->isintegral())
-    {
-	if (e1->type->isfloating())
-	{   integer_t result;
-	    real_t r = e1->toReal();
-
-	    switch (type->toBasetype()->ty)
-	    {
-		case Tint8:	result = (d_int8)r;	break;
-		case Tchar:
-		case Tuns8:	result = (d_uns8)r;	break;
-		case Tint16:	result = (d_int16)r;	break;
-		case Twchar:
-		case Tuns16:	result = (d_uns16)r;	break;
-		case Tint32:	result = (d_int32)r;	break;
-		case Tdchar:
-		case Tuns32:	result = (d_uns32)r;	break;
-		case Tint64:	result = (d_int64)r;	break;
-		case Tuns64:	result = (d_uns64)r;	break;
-		default:
-		    assert(0);
-	    }
-
-	    e = new IntegerExp(loc, result, type);
-	}
-	else if (type->isunsigned())
-	    e = new IntegerExp(loc, e1->toUInteger(), type);
-	else
-	    e = new IntegerExp(loc, e1->toInteger(), type);
-    }
-    else if (tb->isreal())
-    {   real_t value = e1->toReal();
-
-	e = new RealExp(loc, value, type);
-    }
-    else if (tb->isimaginary())
-    {   real_t value = e1->toImaginary();
-
-	e = new RealExp(loc, value, type);
-    }
-    else if (tb->iscomplex())
-    {   complex_t value = e1->toComplex();
-
-	e = new ComplexExp(loc, value, type);
-    }
-    else if (tb->isscalar())
-	e = new IntegerExp(loc, e1->toInteger(), type);
-    else if (tb->ty == Tvoid)
-	e = EXP_CANT_INTERPRET;
-    else if (tb->ty == Tstruct && e1->op == TOKint64)
-    {	// Struct = 0;
-	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
-	assert(sd);
-	Expressions *elements = new Expressions;
-	for (size_t i = 0; i < sd->fields.dim; i++)
-	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
-	    VarDeclaration *v = s->isVarDeclaration();
-	    assert(v);
-
-	    Expression *exp = new IntegerExp(0);
-	    exp = Cast(v->type, v->type, exp);
-	    if (exp == EXP_CANT_INTERPRET)
-		return exp;
-	    elements->push(exp);
-	}
-	e = new StructLiteralExp(loc, sd, elements);
-	e->type = type;
-    }
-    else
-    {
-	error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
-	e = new IntegerExp(loc, 0, type);
-    }
-    return e;
-}
-
-
-Expression *ArrayLength(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (e1->op == TOKstring)
-    {	StringExp *es1 = (StringExp *)e1;
-
-	e = new IntegerExp(loc, es1->len, type);
-    }
-    else if (e1->op == TOKarrayliteral)
-    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	size_t dim;
-
-	dim = ale->elements ? ale->elements->dim : 0;
-	e = new IntegerExp(loc, dim, type);
-    }
-    else if (e1->op == TOKassocarrayliteral)
-    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
-	size_t dim = ale->keys->dim;
-
-	e = new IntegerExp(loc, dim, type);
-    }
-    else
-	e = EXP_CANT_INTERPRET;
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Index(Type *type, Expression *e1, Expression *e2)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-    assert(e1->type);
-    if (e1->op == TOKstring && e2->op == TOKint64)
-    {	StringExp *es1 = (StringExp *)e1;
-	uinteger_t i = e2->toInteger();
-
-	if (i >= es1->len)
-        e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len);
-	else
-	{   unsigned value = es1->charAt(i);
-	    e = new IntegerExp(loc, value, type);
-	}
-    }
-    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
-    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
-	uinteger_t length = tsa->dim->toInteger();
-	uinteger_t i = e2->toInteger();
-
-	if (i >= length)
-	{
-        e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
-	}
-	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
-	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	    e = (Expression *)ale->elements->data[i];
-	    e->type = type;
-	}
-    }
-    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
-    {
-	uinteger_t i = e2->toInteger();
-
-	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
-	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	    if (i >= ale->elements->dim)
-	    {
-            e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
-	    }
-	    else
-	    {	e = (Expression *)ale->elements->data[i];
-		e->type = type;
-	    }
-	}
-    }
-    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
-    {
-	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
-	/* Search the keys backwards, in case there are duplicate keys
-	 */
-	for (size_t i = ae->keys->dim; i;)
-	{
-	    i--;
-	    Expression *ekey = (Expression *)ae->keys->data[i];
-	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
-	    if (ex == EXP_CANT_INTERPRET)
-		return ex;
-	    if (ex->isBool(TRUE))
-	    {	e = (Expression *)ae->values->data[i];
-		e->type = type;
-		break;
-	    }
-	}
-    }
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-#if LOG
-    printf("Slice()\n");
-    if (lwr)
-    {	printf("\te1 = %s\n", e1->toChars());
-	printf("\tlwr = %s\n", lwr->toChars());
-	printf("\tupr = %s\n", upr->toChars());
-    }
-#endif
-    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
-    {	StringExp *es1 = (StringExp *)e1;
-	uinteger_t ilwr = lwr->toInteger();
-	uinteger_t iupr = upr->toInteger();
-
-	if (iupr > es1->len || ilwr > iupr)
-        e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
-	else
-	{   integer_t value;
-	    void *s;
-	    size_t len = iupr - ilwr;
-	    int sz = es1->sz;
-	    StringExp *es;
-
-	    s = mem.malloc((len + 1) * sz);
-	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
-	    memset((unsigned char *)s + len * sz, 0, sz);
-
-	    es = new StringExp(loc, s, len, es1->postfix);
-	    es->sz = sz;
-	    es->committed = 1;
-	    es->type = type;
-	    e = es;
-	}
-    }
-    else if (e1->op == TOKarrayliteral &&
-	    lwr->op == TOKint64 && upr->op == TOKint64 &&
-	    !e1->checkSideEffect(2))
-    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	uinteger_t ilwr = lwr->toInteger();
-	uinteger_t iupr = upr->toInteger();
-
-	if (iupr > es1->elements->dim || ilwr > iupr)
-        e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
-	else
-	{
-	    Expressions *elements = new Expressions();
-	    elements->setDim(iupr - ilwr);
-	    memcpy(elements->data,
-		   es1->elements->data + ilwr,
-		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
-	    e = new ArrayLiteralExp(e1->loc, elements);
-	    e->type = type;
-	}
-    }
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Cat(Type *type, Expression *e1, Expression *e2)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-    Type *t;
-
-    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
-    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
-    {	e = e2;
-	goto L2;
-    }
-    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
-    {	e = e1;
-     L2:
-	Type *tn = e->type->toBasetype();
-	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
-	{
-	    // Create a StringExp
-	    void *s;
-	    StringExp *es;
-	    size_t len = 1;
-	    int sz = tn->size();
-	    integer_t v = e->toInteger();
-
-	    s = mem.malloc((len + 1) * sz);
-	    memcpy((unsigned char *)s, &v, sz);
-
-	    // Add terminating 0
-	    memset((unsigned char *)s + len * sz, 0, sz);
-
-	    es = new StringExp(loc, s, len);
-	    es->sz = sz;
-	    es->committed = 1;
-	    e = es;
-	}
-	else
-	{   // Create an ArrayLiteralExp
-	    Expressions *elements = new Expressions();
-	    elements->push(e);
-	    e = new ArrayLiteralExp(e->loc, elements);
-	}
-	e->type = type;
-	return e;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKstring)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es1 = (StringExp *)e1;
-	StringExp *es2 = (StringExp *)e2;
-	StringExp *es;
-	Type *t;
-	size_t len = es1->len + es2->len;
-	int sz = es1->sz;
-
-	assert(sz == es2->sz);
-	s = mem.malloc((len + 1) * sz);
-	memcpy(s, es1->string, es1->len * sz);
-	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es1->committed | es2->committed;
-	if (es1->committed)
-	    t = es1->type;
-	else
-	    t = es2->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKint64)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es1 = (StringExp *)e1;
-	StringExp *es;
-	Type *t;
-	size_t len = es1->len + 1;
-	int sz = es1->sz;
-	integer_t v = e2->toInteger();
-
-	s = mem.malloc((len + 1) * sz);
-	memcpy(s, es1->string, es1->len * sz);
-	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es1->committed;
-	t = es1->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKint64 && e2->op == TOKstring)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es2 = (StringExp *)e2;
-	StringExp *es;
-	Type *t;
-	size_t len = 1 + es2->len;
-	int sz = es2->sz;
-	integer_t v = e1->toInteger();
-
-	s = mem.malloc((len + 1) * sz);
-	memcpy((unsigned char *)s, &v, sz);
-	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es2->committed;
-	t = es2->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
-	e1->type->equals(e2->type))
-    {
-	// Concatenate the arrays
-	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
-	es1->elements->insert(es1->elements->dim, es2->elements);
-	e = es1;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e1->op == TOKarrayliteral &&
-	e1->type->toBasetype()->nextOf()->equals(e2->type))
-    {
-	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-
-	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
-	es1->elements->push(e2);
-	e = es1;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e2->op == TOKarrayliteral &&
-	e2->type->toBasetype()->nextOf()->equals(e1->type))
-    {
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
-	es2->elements->shift(e1);
-	e = es2;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e1->op == TOKnull && e2->op == TOKstring)
-    {
-	t = e1->type;
-	e = e2;
-	goto L1;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKnull)
-    {	e = e1;
-	t = e2->type;
-      L1:
-	Type *tb = t->toBasetype();
-	if (tb->ty == Tarray && tb->nextOf()->equals(e->type))
-	{   Expressions *expressions = new Expressions();
-	    expressions->push(e);
-	    e = new ArrayLiteralExp(loc, expressions);
-	    e->type = t;
-	}
-	if (!e->type->equals(type))
-	{   StringExp *se = (StringExp *)e->copy();
-	    e = se->castTo(NULL, type);
-	}
-    }
-    return e;
-}
-
-Expression *Ptr(Type *type, Expression *e1)
-{
-    //printf("Ptr(e1 = %s)\n", e1->toChars());
-    if (e1->op == TOKadd)
-    {	AddExp *ae = (AddExp *)e1;
-	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
-	{   AddrExp *ade = (AddrExp *)ae->e1;
-	    if (ade->e1->op == TOKstructliteral)
-	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
-		unsigned offset = ae->e2->toInteger();
-		Expression *e = se->getField(type, offset);
-		if (!e)
-		    e = EXP_CANT_INTERPRET;
-		return e;
-	    }
-	}
-    }
-    return EXP_CANT_INTERPRET;
-}
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+#define LOG 0
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+	e = e->copy();
+	e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int Expression::isConst()
+{
+    //printf("Expression::isConst(): %s\n", toChars());
+    return 0;
+}
+
+int IntegerExp::isConst()
+{
+    return 1;
+}
+
+int RealExp::isConst()
+{
+    return 1;
+}
+
+int ComplexExp::isConst()
+{
+    return 1;
+}
+
+int SymOffExp::isConst()
+{
+    return 2;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+Expression *Neg(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+	e = new RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+	e = new RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+	e = new ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+	e = new IntegerExp(loc, -e1->toInteger(), type);
+    return e;
+}
+
+Expression *Com(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, ~e1->toInteger(), type);
+    return e;
+}
+
+Expression *Not(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(0), type);
+    return e;
+}
+
+Expression *Bool(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(1), type);
+    return e;
+}
+
+Expression *Add(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 + r2);	break;
+	    case 0+1:	v = r1 + i2 * I;		break;
+	    case 0+2:	v = r1 + c2;			break;
+	    case 3+0:	v = i1 * I + r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
+	    case 3+2:	v = i1 * I + c2;		break;
+	    case 6+0:	v = c1 + r2;			break;
+	    case 6+1:	v = c1 + i2 * I;		break;
+	    case 6+2:	v = c1 + c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, i2);		break;
+	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
+	    case 3+0:	v = complex_t(r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 + i2);	break;
+	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
+	    case 6+2:	v = c1 + c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+	e->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e2;
+	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+	e->type = type;
+    }
+    else
+	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return e;
+}
+
+
+Expression *Min(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 - r2);	break;
+	    case 0+1:	v = r1 - i2 * I;		break;
+	    case 0+2:	v = r1 - c2;			break;
+	    case 3+0:	v = i1 * I - r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
+	    case 3+2:	v = i1 * I - c2;		break;
+	    case 6+0:	v = c1 - r2;			break;
+	    case 6+1:	v = c1 - i2 * I;		break;
+	    case 6+2:	v = c1 - c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, -i2);		break;
+	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
+	    case 3+0:	v = complex_t(-r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 - i2);	break;
+	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
+	    case 6+2:	v = c1 - c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+	e->type = type;
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Mul(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	if (e1->type->isreal())
+	{
+#if __DMC__
+	    c = e1->toReal() * e2->toComplex();
+#else
+	    r = e1->toReal();
+	    c = e2->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e1->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toImaginary() * I * e2->toComplex();
+#else
+	    r = e1->toImaginary();
+	    c = e2->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else if (e2->type->isreal())
+	{
+#if __DMC__
+	    c = e2->toReal() * e1->toComplex();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toComplex() * e2->toImaginary() * I;
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else
+	    c = e1->toComplex() * e2->toComplex();
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Div(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	//e1->type->print();
+	//e2->type->print();
+	if (e2->type->isreal())
+	{
+	    if (e1->type->isreal())
+	    {
+		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
+		return e;
+	    }
+#if __DMC__
+	    //r = e2->toReal();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / e2->toReal();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(creall(c) / r, cimagl(c) / r);
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    //r = e2->toImaginary();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / (e2->toImaginary() * I);
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(cimagl(c) / r, -creall(c) / r);
+#endif
+	}
+	else
+	{
+	    c = e1->toComplex() / e2->toComplex();
+	}
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) / ((d_uns64) n2);
+	else
+	    n = n1 / n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Mod(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+	complex_t c;
+
+	if (e2->type->isreal())
+	{   real_t r2 = e2->toReal();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{   real_t i2 = e2->toImaginary();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+#endif
+	}
+	else
+	    assert(0);
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) % ((d_uns64) n2);
+	else
+	    n = n1 % n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Shl(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return e;
+}
+
+Expression *Shr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+		value = (d_int8)(value) >> count;
+		break;
+
+	case Tuns8:
+		value = (d_uns8)(value) >> count;
+		break;
+
+	case Tint16:
+		value = (d_int16)(value) >> count;
+		break;
+
+	case Tuns16:
+		value = (d_uns16)(value) >> count;
+		break;
+
+	case Tint32:
+		value = (d_int32)(value) >> count;
+		break;
+
+	case Tuns32:
+		value = (d_uns32)(value) >> count;
+		break;
+
+	case Tint64:
+		value = (d_int64)(value) >> count;
+		break;
+
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *Ushr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+	case Tuns8:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFF) >> count;
+		break;
+
+	case Tint16:
+	case Tuns16:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFFFF) >> count;
+		break;
+
+	case Tint32:
+	case Tuns32:
+		value = (value & 0xFFFFFFFF) >> count;
+		break;
+
+	case Tint64:
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *And(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
+    return e;
+}
+
+Expression *Or(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
+    return e;
+}
+
+Expression *Xor(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ */
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKnull)
+    {
+	if (e2->op == TOKnull)
+	    cmp = 1;
+	else if (e2->op == TOKstring)
+	{   StringExp *es2 = (StringExp *)e2;
+	    cmp = (0 == es2->len);
+	}
+	else if (e2->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	    cmp = !es2->elements || (0 == es2->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e2->op == TOKnull)
+    {
+	if (e1->op == TOKstring)
+	{   StringExp *es1 = (StringExp *)e1;
+	    cmp = (0 == es1->len);
+	}
+	else if (e1->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	    cmp = !es1->elements || (0 == es1->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+
+	assert(es1->sz == es2->sz);
+	if (es1->len == es2->len &&
+	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+	    cmp = 1;
+	else
+	    cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {	// Swap operands and use common code
+	Expression *e = e1;
+	e1 = e2;
+	e2 = e;
+	goto Lsa;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
+    {
+     Lsa:
+	StringExp *es1 = (StringExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	size_t dim1 = es1->len;
+	size_t dim2 = es2->elements ? es2->elements->dim : 0;
+	if (dim1 != dim2)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < dim1; i++)
+	    {
+		uinteger_t c = es1->charAt(i);
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+		if (ee2->isConst() != 1)
+		    return EXP_CANT_INTERPRET;
+		cmp = (c == ee2->toInteger());
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
+	StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+	if (es1->sd != es2->sd)
+	    cmp = 0;
+	else if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    cmp = 1;
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		if (ee1 == ee2)
+		    continue;
+		if (!ee1 || !ee2)
+		{   cmp = 0;
+		    break;
+		}
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+#if 0 // Should handle this
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+    }
+#endif
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	cmp = (r1 == r2);
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+	{
+	    cmp = 0;
+	}
+	else
+	{
+	    cmp = (r1 == r2);
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral())
+    {
+	cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+	return EXP_CANT_INTERPRET;
+    if (op == TOKnotequal)
+	cmp ^= 1;
+    e = new IntegerExp(loc, cmp, type);
+    return e;
+}
+
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKnull && e2->op == TOKnull)
+    {
+	cmp = 1;
+    }
+    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+	SymOffExp *es1 = (SymOffExp *)e1;
+	SymOffExp *es2 = (SymOffExp *)e2;
+
+	cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->isConst() == 1 && e2->isConst() == 1)
+	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+		type, e1, e2);
+    else
+	assert(0);
+    if (op == TOKnotidentity)
+	cmp ^= 1;
+    return new IntegerExp(loc, cmp, type);
+}
+
+
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    integer_t n;
+    real_t r1;
+    real_t r2;
+
+    if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	// DMC is the only compiler I know of that handles NAN arguments
+	// correctly in comparisons.
+	switch (op)
+	{
+	    case TOKlt:	   n = r1 <  r2;	break;
+	    case TOKle:	   n = r1 <= r2;	break;
+	    case TOKgt:	   n = r1 >  r2;	break;
+	    case TOKge:	   n = r1 >= r2;	break;
+
+	    case TOKleg:   n = r1 <>=  r2;	break;
+	    case TOKlg:	   n = r1 <>   r2;	break;
+	    case TOKunord: n = r1 !<>= r2;	break;
+	    case TOKue:	   n = r1 !<>  r2;	break;
+	    case TOKug:	   n = r1 !<=  r2;	break;
+	    case TOKuge:   n = r1 !<   r2;	break;
+	    case TOKul:	   n = r1 !>=  r2;	break;
+	    case TOKule:   n = r1 !>   r2;	break;
+
+	    default:
+		assert(0);
+	}
+#else
+	// Don't rely on compiler, handle NAN arguments separately
+#if IN_GCC
+	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+#endif
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = 0;	break;
+		case TOKle:	n = 0;	break;
+		case TOKgt:	n = 0;	break;
+		case TOKge:	n = 0;	break;
+
+		case TOKleg:	n = 0;	break;
+		case TOKlg:	n = 0;	break;
+		case TOKunord:	n = 1;	break;
+		case TOKue:	n = 1;	break;
+		case TOKug:	n = 1;	break;
+		case TOKuge:	n = 1;	break;
+		case TOKul:	n = 1;	break;
+		case TOKule:	n = 1;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = r1 <  r2;	break;
+		case TOKle:	n = r1 <= r2;	break;
+		case TOKgt:	n = r1 >  r2;	break;
+		case TOKge:	n = r1 >= r2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = r1 != r2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = r1 == r2;	break;
+		case TOKug:	n = r1 >  r2;	break;
+		case TOKuge:	n = r1 >= r2;	break;
+		case TOKul:	n = r1 <  r2;	break;
+		case TOKule:	n = r1 <= r2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+
+		case TOKleg:	n = 1;					break;
+		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
+		case TOKunord:	n = 0;					break;
+		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
+		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = n1 <  n2;	break;
+		case TOKle:	n = n1 <= n2;	break;
+		case TOKgt:	n = n1 >  n2;	break;
+		case TOKge:	n = n1 >= n2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = n1 != n2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = n1 == n2;	break;
+		case TOKug:	n = n1 >  n2;	break;
+		case TOKuge:	n = n1 >= n2;	break;
+		case TOKul:	n = n1 <  n2;	break;
+		case TOKule:	n = n1 <= n2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    e = new IntegerExp(loc, n, type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ *  to:	type to cast to
+ *  type: type to paint the result
+ */
+
+Expression *Cast(Type *type, Type *to, Expression *e1)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("e1->type = %s\n", e1->type->toChars());
+    if (type->equals(e1->type) && to->equals(type))
+	return e1;
+
+    if (e1->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+
+    Type *tb = to->toBasetype();
+    if (tb->ty == Tbool)
+	e = new IntegerExp(loc, e1->toInteger() != 0, type);
+    else if (type->isintegral())
+    {
+	if (e1->type->isfloating())
+	{   integer_t result;
+	    real_t r = e1->toReal();
+
+	    switch (type->toBasetype()->ty)
+	    {
+		case Tint8:	result = (d_int8)r;	break;
+		case Tchar:
+		case Tuns8:	result = (d_uns8)r;	break;
+		case Tint16:	result = (d_int16)r;	break;
+		case Twchar:
+		case Tuns16:	result = (d_uns16)r;	break;
+		case Tint32:	result = (d_int32)r;	break;
+		case Tdchar:
+		case Tuns32:	result = (d_uns32)r;	break;
+		case Tint64:	result = (d_int64)r;	break;
+		case Tuns64:	result = (d_uns64)r;	break;
+		default:
+		    assert(0);
+	    }
+
+	    e = new IntegerExp(loc, result, type);
+	}
+	else if (type->isunsigned())
+	    e = new IntegerExp(loc, e1->toUInteger(), type);
+	else
+	    e = new IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {   real_t value = e1->toReal();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {   real_t value = e1->toImaginary();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {   complex_t value = e1->toComplex();
+
+	e = new ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+	e = new IntegerExp(loc, e1->toInteger(), type);
+    else if (tb->ty == Tvoid)
+	e = EXP_CANT_INTERPRET;
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {	// Struct = 0;
+	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+	assert(sd);
+	Expressions *elements = new Expressions;
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    Expression *exp = new IntegerExp(0);
+	    exp = Cast(v->type, v->type, exp);
+	    if (exp == EXP_CANT_INTERPRET)
+		return exp;
+	    elements->push(exp);
+	}
+	e = new StructLiteralExp(loc, sd, elements);
+	e->type = type;
+    }
+    else
+    {
+	error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
+	e = new IntegerExp(loc, 0, type);
+    }
+    return e;
+}
+
+
+Expression *ArrayLength(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+
+	e = new IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	size_t dim;
+
+	dim = ale->elements ? ale->elements->dim : 0;
+	e = new IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+	size_t dim = ale->keys->dim;
+
+	e = new IntegerExp(loc, dim, type);
+    }
+    else
+	e = EXP_CANT_INTERPRET;
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Index(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t i = e2->toInteger();
+
+	if (i >= es1->len)
+        e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len);
+	else
+	{   unsigned value = es1->charAt(i);
+	    e = new IntegerExp(loc, value, type);
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+	uinteger_t length = tsa->dim->toInteger();
+	uinteger_t i = e2->toInteger();
+
+	if (i >= length)
+	{
+        e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
+	}
+	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    e = (Expression *)ale->elements->data[i];
+	    e->type = type;
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+	uinteger_t i = e2->toInteger();
+
+	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    if (i >= ale->elements->dim)
+	    {
+            e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+	    }
+	    else
+	    {	e = (Expression *)ale->elements->data[i];
+		e->type = type;
+	    }
+	}
+    }
+    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+    {
+	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+	/* Search the keys backwards, in case there are duplicate keys
+	 */
+	for (size_t i = ae->keys->dim; i;)
+	{
+	    i--;
+	    Expression *ekey = (Expression *)ae->keys->data[i];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+	    if (ex == EXP_CANT_INTERPRET)
+		return ex;
+	    if (ex->isBool(TRUE))
+	    {	e = (Expression *)ae->values->data[i];
+		e->type = type;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {	printf("\te1 = %s\n", e1->toChars());
+	printf("\tlwr = %s\n", lwr->toChars());
+	printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->len || ilwr > iupr)
+        e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{   integer_t value;
+	    void *s;
+	    size_t len = iupr - ilwr;
+	    int sz = es1->sz;
+	    StringExp *es;
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len, es1->postfix);
+	    es->sz = sz;
+	    es->committed = 1;
+	    es->type = type;
+	    e = es;
+	}
+    }
+    else if (e1->op == TOKarrayliteral &&
+	    lwr->op == TOKint64 && upr->op == TOKint64 &&
+	    !e1->checkSideEffect(2))
+    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->elements->dim || ilwr > iupr)
+        e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{
+	    Expressions *elements = new Expressions();
+	    elements->setDim(iupr - ilwr);
+	    memcpy(elements->data,
+		   es1->elements->data + ilwr,
+		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
+	    e = new ArrayLiteralExp(e1->loc, elements);
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Cat(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+    Type *t;
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
+    {	e = e2;
+	goto L2;
+    }
+    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
+    {	e = e1;
+     L2:
+	Type *tn = e->type->toBasetype();
+	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	{
+	    // Create a StringExp
+	    void *s;
+	    StringExp *es;
+	    size_t len = 1;
+	    int sz = tn->size();
+	    integer_t v = e->toInteger();
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, &v, sz);
+
+	    // Add terminating 0
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len);
+	    es->sz = sz;
+	    es->committed = 1;
+	    e = es;
+	}
+	else
+	{   // Create an ArrayLiteralExp
+	    Expressions *elements = new Expressions();
+	    elements->push(e);
+	    e = new ArrayLiteralExp(e->loc, elements);
+	}
+	e->type = type;
+	return e;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + es2->len;
+	int sz = es1->sz;
+
+	assert(sz == es2->sz);
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed | es2->committed;
+	if (es1->committed)
+	    t = es1->type;
+	else
+	    t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + 1;
+	int sz = es1->sz;
+	integer_t v = e2->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed;
+	t = es1->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = 1 + es2->len;
+	int sz = es2->sz;
+	integer_t v = e1->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy((unsigned char *)s, &v, sz);
+	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es2->committed;
+	t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+	e1->type->equals(e2->type))
+    {
+	// Concatenate the arrays
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->insert(es1->elements->dim, es2->elements);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
+	e1->type->toBasetype()->nextOf()->equals(e2->type))
+    {
+	ArrayLiteralExp *es1;
+	if (e1->op == TOKarrayliteral)
+	{   es1 = (ArrayLiteralExp *)e1;
+	    es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	    es1->elements->push(e2);
+	}
+	else
+	{
+	    es1 = new ArrayLiteralExp(e1->loc, e2);
+	}
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e2->op == TOKarrayliteral &&
+	e2->type->toBasetype()->nextOf()->equals(e1->type))
+    {
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
+	es2->elements->shift(e1);
+	e = es2;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+	t = e1->type;
+	e = e2;
+	goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {	e = e1;
+	t = e2->type;
+      L1:
+	Type *tb = t->toBasetype();
+	if (tb->ty == Tarray && tb->nextOf()->equals(e->type))
+	{   Expressions *expressions = new Expressions();
+	    expressions->push(e);
+	    e = new ArrayLiteralExp(loc, expressions);
+	    e->type = t;
+	}
+	if (!e->type->equals(type))
+	{   StringExp *se = (StringExp *)e->copy();
+	    e = se->castTo(NULL, type);
+	}
+    }
+    return e;
+}
+
+Expression *Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    if (ade->e1->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+		unsigned offset = ae->e2->toInteger();
+		Expression *e = se->getField(type, offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+    return EXP_CANT_INTERPRET;
+}
+
--- a/dmd/declaration.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/declaration.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -39,7 +39,7 @@
 {
 }
 
-char *Declaration::kind()
+const char *Declaration::kind()
 {
     return "declaration";
 }
@@ -80,6 +80,76 @@
     return protection;
 }
 
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ */
+
+#if DMDV2
+void Declaration::checkModify(Loc loc, Scope *sc, Type *t)
+{
+    if (sc->incontract && isParameter())
+	error(loc, "cannot modify parameter '%s' in contract", toChars());
+
+    if (isCtorinit())
+    {	// It's only modifiable if inside the right constructor
+	Dsymbol *s = sc->func;
+	while (1)
+	{
+	    FuncDeclaration *fd = NULL;
+	    if (s)
+		fd = s->isFuncDeclaration();
+	    if (fd &&
+		((fd->isCtorDeclaration() && storage_class & STCfield) ||
+		 (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) &&
+		fd->toParent() == toParent()
+	       )
+	    {
+		VarDeclaration *v = isVarDeclaration();
+		assert(v);
+		v->ctorinit = 1;
+		//printf("setting ctorinit\n");
+	    }
+	    else
+	    {
+		if (s)
+		{   s = s->toParent2();
+		    continue;
+		}
+		else
+		{
+		    const char *p = isStatic() ? "static " : "";
+		    error(loc, "can only initialize %sconst %s inside %sconstructor",
+			p, toChars(), p);
+		}
+	    }
+	    break;
+	}
+    }
+    else
+    {
+	VarDeclaration *v = isVarDeclaration();
+	if (v && v->canassign == 0)
+	{
+	    char *p = NULL;
+	    if (isConst())
+		p = "const";
+	    else if (isInvariant())
+		p = "invariant";
+	    else if (storage_class & STCmanifest)
+		p = "manifest constant";
+	    else if (!t->isAssignable())
+		p = "struct with immutable members";
+	    if (p)
+	    {	error(loc, "cannot modify %s", p);
+		halt();
+	    }
+	}
+    }
+}
+#endif
+
+
 /********************************* TupleDeclaration ****************************/
 
 TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
@@ -97,7 +167,7 @@
     return NULL;
 }
 
-char *TupleDeclaration::kind()
+const char *TupleDeclaration::kind()
 {
     return "tuple";
 }
@@ -231,6 +301,7 @@
 	type = type->semantic(loc, sc);
 	if (sc->parent->isFuncDeclaration() && init)
 	    semantic2(sc);
+	storage_class |= sc->stc & STCdeprecated;
     }
     else if (sem == 1)
     {
@@ -257,7 +328,7 @@
     }
 }
 
-char *TypedefDeclaration::kind()
+const char *TypedefDeclaration::kind()
 {
     return "typedef";
 }
@@ -318,6 +389,7 @@
 
 Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
 {
+    //printf("AliasDeclaration::syntaxCopy()\n");
     assert(!s);
     AliasDeclaration *sa;
     if (type)
@@ -466,7 +538,7 @@
     }
 }
 
-char *AliasDeclaration::kind()
+const char *AliasDeclaration::kind()
 {
     return "alias";
 }
@@ -601,7 +673,9 @@
 void VarDeclaration::semantic(Scope *sc)
 {
     //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
-    //printf("type = %s\n", type->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();
 
@@ -629,6 +703,7 @@
 	    originalType = type;
 	type = type->semantic(loc, sc);
     }
+    //printf(" semantic type = %s\n", type ? type->toChars() : "null");
 
     type->checkDeprecated(loc, sc);
     linkage = sc->linkage;
@@ -636,7 +711,7 @@
     //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\n", storage_class);
+    //printf("storage_class = x%x\n", storage_class);
 
     Dsymbol *parent = toParent();
     FuncDeclaration *fd = parent->isFuncDeclaration();
@@ -749,6 +824,8 @@
 	    error("field not allowed in interface");
 	}
 
+	/* Templates cannot add fields to aggregates
+	 */
 	TemplateInstance *ti = parent->isTemplateInstance();
 	if (ti)
 	{
@@ -853,10 +930,6 @@
 	    // possibilities.
 	    if (fd && !isStatic() && !isConst() && !init->isVoidInitializer())
 	    {
-		Expression *e1;
-		Type *t;
-		int dim;
-
 		//printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
 		if (!ei)
 		{
@@ -874,15 +947,15 @@
 		    init = ei;
 		}
 
-		e1 = new VarExp(loc, this);
+		Expression *e1 = new VarExp(loc, this);
 
-		t = type->toBasetype();
+		Type *t = type->toBasetype();
 		if (t->ty == Tsarray)
 		{
 		    ei->exp = ei->exp->semantic(sc);
 		    if (!ei->exp->implicitConvTo(type))
 		    {
-			dim = ((TypeSArray *)t)->dim->toInteger();
+			int dim = ((TypeSArray *)t)->dim->toInteger();
 			// If multidimensional static array, treat as one large array
 			while (1)
 			{
@@ -974,7 +1047,7 @@
 	ei = init->isExpInitializer();
     else
     {
-	Expression *e = type->defaultInit();
+	Expression *e = type->defaultInit(loc);
 	if (e)
 	    ei = new ExpInitializer(loc, e);
 	else
@@ -1001,7 +1074,7 @@
     }
 }
 
-char *VarDeclaration::kind()
+const char *VarDeclaration::kind()
 {
     return "variable";
 }
@@ -1020,6 +1093,17 @@
 	buf->writestring("const ");
     if (storage_class & STCstatic)
 	buf->writestring("static ");
+    if (storage_class & STCauto)
+	buf->writestring("auto ");
+#if DMDV2
+    if (storage_class & STCmanifest)
+	buf->writestring("manifest ");
+    if (storage_class & STCinvariant)
+	buf->writestring("invariant ");
+    if (storage_class & STCtls)
+	buf->writestring("__thread ");
+#endif
+
     if (type)
 	type->toCBuffer(buf, ident, hgs);
     else
@@ -1052,15 +1136,18 @@
 }
 
 /************************************
- * Check to see if variable is a reference to an enclosing function
- * or not.
+ * Check to see if this variable is actually in an enclosing function
+ * rather than the current one.
  */
 
 void VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
 {
+    //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
     if (parent && !isDataseg() && parent != sc->parent)
     {
+	// The function that this variable is in
 	FuncDeclaration *fdv = toParent()->isFuncDeclaration();
+	// The current function
 	FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
 
 	if (fdv && fdthis)
@@ -1077,6 +1164,7 @@
 
 /*******************************
  * Does symbol go into data segment?
+ * Includes extern variables.
  */
 
 int VarDeclaration::isDataseg()
@@ -1201,7 +1289,7 @@
 
 /***************************** TypeInfoConstDeclaration **********************/
 
-#if V2
+#if DMDV2
 TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo)
     : TypeInfoDeclaration(tinfo, 0)
 {
@@ -1210,7 +1298,7 @@
 
 /***************************** TypeInfoInvariantDeclaration **********************/
 
-#if V2
+#if DMDV2
 TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo)
     : TypeInfoDeclaration(tinfo, 0)
 {
--- a/dmd/declaration.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/declaration.h	Sat Jul 12 19:38:31 2008 +0200
@@ -73,6 +73,7 @@
     STCnothrow	    = 0x2000000,	// never throws exceptions
     STCpure	    = 0x4000000,	// pure function
     STCtls	    = 0x8000000,	// thread local
+    STCalias	    = 0x10000000,	// alias parameter
 };
 
 struct Match
@@ -101,7 +102,7 @@
 
     Declaration(Identifier *id);
     void semantic(Scope *sc);
-    char *kind();
+    const char *kind();
     unsigned size(Loc loc);
     void checkModify(Loc loc, Scope *sc, Type *t);
 
@@ -150,7 +151,7 @@
 
     TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
     Dsymbol *syntaxCopy(Dsymbol *);
-    char *kind();
+    const char *kind();
     Type *getType();
     int needThis();
 
@@ -174,7 +175,7 @@
     void semantic(Scope *sc);
     void semantic2(Scope *sc);
     char *mangle();
-    char *kind();
+    const char *kind();
     Type *getType();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 #ifdef _DH
@@ -184,7 +185,7 @@
 
     void toDocBuffer(OutBuffer *buf);
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     void toDebug();
     int cvMember(unsigned char *p);
 
@@ -207,7 +208,7 @@
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     int overloadInsert(Dsymbol *s);
-    char *kind();
+    const char *kind();
     Type *getType();
     Dsymbol *toAlias();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -242,7 +243,7 @@
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     void semantic2(Scope *sc);
-    char *kind();
+    const char *kind();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 #ifdef _DH
     Type *htype;
@@ -259,7 +260,7 @@
     Dsymbol *toAlias();
 
     Symbol *toSymbol();
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     int cvMember(unsigned char *p);
 
     // Eliminate need for dynamic_cast
@@ -325,7 +326,7 @@
     void emitComment(Scope *sc);
 
     Symbol *toSymbol();
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     virtual void toDt(dt_t **pdt);
 
     virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; }
@@ -467,6 +468,32 @@
     void llvmDefine();
 };
 
+#if DMDV2
+struct TypeInfoConstDeclaration : TypeInfoDeclaration
+{
+    TypeInfoConstDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+
+    // LLVMDC
+    void llvmDeclare();
+    void llvmDefine();
+};
+
+struct TypeInfoInvariantDeclaration : TypeInfoDeclaration
+{
+    TypeInfoInvariantDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+
+    // LLVMDC
+    void llvmDeclare();
+    void llvmDefine();
+};
+#endif
+
+/**************************************************************/
+
 struct ThisDeclaration : VarDeclaration
 {
     ThisDeclaration(Type *t);
@@ -481,8 +508,7 @@
 };
 
 /**************************************************************/
-
-#if V2
+#if DMDV2
 
 enum BUILTIN
 {
@@ -548,7 +574,7 @@
     VarDeclaration *nrvo_var;		// variable to replace with shidden
     Symbol *shidden;			// hidden pointer passed to function
 
-#if V2
+#if DMDV2
     enum BUILTIN builtin;		// set if this is a known, builtin
 					// function we can evaluate at compile
 					// time
@@ -597,7 +623,7 @@
     void inlineScan();
     int canInline(int hasthis, int hdrscan = 0);
     Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments);
-    char *kind();
+    const char *kind();
     void toDocBuffer(OutBuffer *buf);
 
     static FuncDeclaration *genCfunc(Type *treturn, char *name);
@@ -605,7 +631,7 @@
 
     Symbol *toSymbol();
     Symbol *toThunkSymbol(int offset);	// thunk version
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     int cvMember(unsigned char *p);
 
     FuncDeclaration *isFuncDeclaration() { return this; }
@@ -627,7 +653,7 @@
     FuncAliasDeclaration(FuncDeclaration *funcalias);
 
     FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
-    char *kind();
+    const char *kind();
     Symbol *toSymbol();
 };
 
@@ -640,9 +666,10 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Dsymbol *syntaxCopy(Dsymbol *);
     int isNested();
+    int isVirtual();
 
     FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
-    char *kind();
+    const char *kind();
 };
 
 struct CtorDeclaration : FuncDeclaration
@@ -653,7 +680,7 @@
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
     char *toChars();
     int isVirtual();
     int addPreInvariant();
@@ -663,6 +690,24 @@
     CtorDeclaration *isCtorDeclaration() { return this; }
 };
 
+#if DMDV2
+struct PostBlitDeclaration : FuncDeclaration
+{
+    PostBlitDeclaration(Loc loc, Loc endloc);
+    PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    int overloadInsert(Dsymbol *s);
+    void emitComment(Scope *sc);
+
+    PostBlitDeclaration *isPostBlitDeclaration() { return this; }
+};
+#endif
+
 struct DtorDeclaration : FuncDeclaration
 {
     DtorDeclaration(Loc loc, Loc endloc);
@@ -696,7 +741,8 @@
 };
 
 struct StaticDtorDeclaration : FuncDeclaration
-{
+{   VarDeclaration *vgate;	// 'gate' variable
+
     StaticDtorDeclaration(Loc loc, Loc endloc);
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
@@ -748,7 +794,7 @@
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
     int isVirtual();
     int addPreInvariant();
     int addPostInvariant();
@@ -764,7 +810,7 @@
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
     int isDelete();
     int isVirtual();
     int addPreInvariant();
--- a/dmd/doc.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/doc.c	Sat Jul 12 19:38:31 2008 +0200
@@ -400,7 +400,7 @@
 
 void ScopeDsymbol::emitMemberComments(Scope *sc)
 {
-    //printf("ScopeDsymbol::emitMemberComments()\n");
+    //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars());
     OutBuffer *buf = sc->docbuf;
 
     if (members)
@@ -417,8 +417,9 @@
 	else if (isTemplateDeclaration())
 	    m = "$(DDOC_TEMPLATE_MEMBERS \n";
 
-	// BUG: if no members are actually printed, we should not emit DDOC_MEMBERS
+	unsigned offset1 = buf->offset;		// save starting offset
 	buf->writestring(m);
+	unsigned offset2 = buf->offset;		// to see if we write anything
 	sc = sc->push(this);
 	for (int i = 0; i < members->dim; i++)
 	{
@@ -427,7 +428,14 @@
 	    s->emitComment(sc);
 	}
 	sc->pop();
-	buf->writestring(")\n");
+	if (buf->offset == offset2)
+	{
+	    /* Didn't write out any members, so back out last write
+	     */
+	    buf->offset = offset1;
+	}
+	else
+	    buf->writestring(")\n");
     }
 }
 
@@ -448,7 +456,9 @@
 
 void Dsymbol::emitComment(Scope *sc)		   { }
 void InvariantDeclaration::emitComment(Scope *sc)  { }
-//void PostBlitDeclaration::emitComment(Scope *sc)   { }
+#if DMDV2
+void PostBlitDeclaration::emitComment(Scope *sc)   { }
+#endif
 void DtorDeclaration::emitComment(Scope *sc)	   { }
 void StaticCtorDeclaration::emitComment(Scope *sc) { }
 void StaticDtorDeclaration::emitComment(Scope *sc) { }
@@ -525,12 +535,8 @@
     //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind());
     if (prot() == PROTprivate)
 	return;
-    if (!comment)
-	return;
 
-    OutBuffer *buf = sc->docbuf;
-    DocComment *dc = DocComment::parse(sc, this, comment);
-    unsigned o;
+    unsigned char *com = comment;
     int hasmembers = 1;
 
     Dsymbol *ss = this;
@@ -542,12 +548,22 @@
 	{
 	    ss = onemember->isFuncDeclaration();
 	    if (ss)
-		hasmembers = 0;
+	    {	hasmembers = 0;
+		if (com != ss->comment)
+		    com = Lexer::combineComments(com, ss->comment);
+	    }
 	    else
 		ss = this;
 	}
     }
 
+    if (!com)
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, com);
+    unsigned o;
+
     if (!dc)
     {
 	ss->emitDitto(sc);
@@ -667,7 +683,7 @@
 	    buf->writestring("static ");
 	if (d->isConst())
 	    buf->writestring("const ");
-#if V2
+#if DMDV2
 	if (d->isInvariant())
 	    buf->writestring("invariant ");
 #endif
@@ -743,7 +759,9 @@
 	if (parent &&
 	    (td = parent->isTemplateDeclaration()) != NULL &&
 	    td->onemember == this)
-	{   HdrGenState hgs;
+	{   /* It's a function template
+	     */
+	    HdrGenState hgs;
 	    unsigned o = buf->offset;
 	    TypeFunction *tf = (TypeFunction *)type;
 
@@ -1581,7 +1599,13 @@
      */
     if (f && f->type)
     {
-	TypeFunction *tf = (TypeFunction *)f->type;
+	TypeFunction *tf;
+	if (f->originalType)
+	{
+	    tf = (TypeFunction *)f->originalType;
+	}
+	else
+	    tf = (TypeFunction *)f->type;
 
 	if (tf->parameters)
 	{
--- a/dmd/dsymbol.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/dsymbol.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -201,7 +201,7 @@
     return loc.toChars();
 }
 
-char *Dsymbol::kind()
+const char *Dsymbol::kind()
 {
     return "symbol";
 }
@@ -244,6 +244,16 @@
     return s;
 }
 
+TemplateInstance *Dsymbol::inTemplateInstance()
+{
+    for (Dsymbol *parent = this->parent; parent; parent = parent->parent)
+    {
+	TemplateInstance *ti = parent->isTemplateInstance();
+	if (ti)
+	    return ti;
+    }
+    return NULL;
+}
 
 int Dsymbol::isAnonymous()
 {
@@ -270,6 +280,16 @@
     // Most Dsymbols have no further semantic analysis needed
 }
 
+/*********************************************
+ * Search for ident as member of s.
+ * Input:
+ *	flags:	1	don't find private members
+ *		2	don't give error messages
+ *		4	return NULL if ambiguous
+ * Returns:
+ *	NULL if not found
+ */
+
 Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags)
 {
     //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
@@ -389,7 +409,9 @@
 
 AggregateDeclaration *Dsymbol::isMember()	// is this a member of an AggregateDeclaration?
 {
+    //printf("Dsymbol::isMember() %s\n", toChars());
     Dsymbol *parent = toParent();
+    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
     return parent ? parent->isAggregateDeclaration() : NULL;
 }
 
@@ -502,6 +524,10 @@
 	{
 	    if (sc->scopesym && sc->scopesym->isDeprecated())
 		return;
+
+	    // If inside a StorageClassDeclaration that is deprecated
+	    if (sc->stc & STCdeprecated)
+		return;
 	}
 
 	error(loc, "is deprecated");
@@ -617,12 +643,11 @@
 }
 
 Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags)
-{   Dsymbol *s;
-    int i;
+{
+    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
 
-    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
     // Look in symbols declared in this module
-    s = symtab ? symtab->lookup(ident) : NULL;
+    Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;
     if (s)
     {
 	//printf("\ts = '%s.%s'\n",toChars(),s->toChars());
@@ -630,7 +655,7 @@
     else if (imports)
     {
 	// Look in imported modules
-	for (i = 0; i < imports->dim; i++)
+	for (int i = 0; i < imports->dim; i++)
 	{   ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i];
 	    Dsymbol *s2;
 
@@ -639,6 +664,8 @@
 		continue;
 
 	    //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
+	    /* Don't find private members if ss is a module
+	     */
 	    s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
 	    if (!s)
 		s = s2;
@@ -646,6 +673,10 @@
 	    {
 		if (s->toAlias() == s2->toAlias())
 		{
+		    /* After following aliases, we found the same symbol,
+		     * so it's not an ambiguity.
+		     * But if one alias is deprecated, prefer the other.
+		     */
 		    if (s->isDeprecated())
 			s = s2;
 		}
@@ -768,7 +799,7 @@
     return sprev;
 }
 
-char *ScopeDsymbol::kind()
+const char *ScopeDsymbol::kind()
 {
     return "ScopeDsymbol";
 }
@@ -780,7 +811,7 @@
  * Returns NULL if not found
  */
 
-#if V2
+#if DMDV2
 FuncDeclaration *ScopeDsymbol::findGetMembers()
 {
     Dsymbol *s = search_function(this, Id::getmembers);
--- a/dmd/dsymbol.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/dsymbol.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -123,12 +123,13 @@
     Dsymbol *pastMixin();
     Dsymbol *toParent();
     Dsymbol *toParent2();
+    TemplateInstance *inTemplateInstance();
 
     int dyncast() { return DYNCAST_DSYMBOL; }	// kludge for template.isSymbol()
 
     static Array *arraySyntaxCopy(Array *a);
 
-    virtual char *kind();
+    virtual const char *kind();
     virtual Dsymbol *toAlias();			// resolve real symbol
     virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
     virtual void semantic(Scope *sc);
@@ -150,7 +151,7 @@
     virtual AggregateDeclaration *isThis();	// is a 'this' required to access the member
     virtual ClassDeclaration *isClassMember();	// are we a member of a class?
     virtual int isExport();			// is Dsymbol exported?
-    virtual int isImportedSymbol();			// is Dsymbol imported?
+    virtual int isImportedSymbol();		// is Dsymbol imported?
     virtual int isDeprecated();			// is Dsymbol deprecated?
     virtual LabelDsymbol *isLabel();		// is this a LabelDsymbol?
     virtual AggregateDeclaration *isMember();	// is this symbol a member of an AggregateDeclaration?
@@ -172,7 +173,7 @@
     // Backend
 
     virtual Symbol *toSymbol();			// to backend symbol
-    virtual void toObjFile();			// compile to .obj file
+    virtual void toObjFile(int multiobj);			// compile to .obj file
     virtual int cvMember(unsigned char *p);	// emit cv debug info for member
 
     Symbol *toImport();				// to backend import symbol
@@ -247,7 +248,7 @@
     void defineRef(Dsymbol *s);
     static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
     Dsymbol *nameCollision(Dsymbol *s);
-    char *kind();
+    const char *kind();
 
     void emitMemberComments(Scope *sc);
 
--- a/dmd/enum.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/enum.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,5 +1,5 @@
 
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -14,6 +14,7 @@
 #include "enum.h"
 #include "mtype.h"
 #include "scope.h"
+#include "declaration.h"
 
 /********************************* EnumDeclaration ****************************/
 
@@ -27,6 +28,7 @@
     minval = 0;
     defaultval = 0;
     sinit = NULL;
+    isdeprecated = 0;
 }
 
 Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
@@ -57,6 +59,9 @@
 	return;
     if (!memtype)
 	memtype = Type::tint32;
+    if (sc->stc & STCdeprecated)
+	isdeprecated = 1;
+
     parent = sc->scopesym;
     memtype = memtype->semantic(loc, sc);
 
@@ -265,11 +270,16 @@
     return type;
 }
 
-char *EnumDeclaration::kind()
+const char *EnumDeclaration::kind()
 {
     return "enum";
 }
 
+int EnumDeclaration::isDeprecated()
+{
+    return isdeprecated;
+}
+
 /********************************* EnumMember ****************************/
 
 EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value)
@@ -306,7 +316,7 @@
     }
 }
 
-char *EnumMember::kind()
+const char *EnumMember::kind()
 {
     return "enum member";
 }
--- a/dmd/enum.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/enum.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -30,9 +30,19 @@
 {
     Type *type;			// the TypeEnum
     Type *memtype;		// type of the members
+
+#if DMDV1
     integer_t maxval;
     integer_t minval;
     integer_t defaultval;	// default initializer
+#else
+    Expression *maxval;
+    Expression *minval;
+    Expression *defaultval;	// default initializer
+
+    Scope *scope;		// !=NULL means context to use
+#endif
+    int isdeprecated;
 
     EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
     Dsymbol *syntaxCopy(Dsymbol *s);
@@ -40,14 +50,18 @@
     int oneMember(Dsymbol **ps);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Type *getType();
-    char *kind();
+    const char *kind();
+#if DMDV2
+    Dsymbol *search(Loc, Identifier *ident, int flags);
+#endif
+    int isDeprecated();			// is Dsymbol deprecated?
 
     void emitComment(Scope *sc);
     void toDocBuffer(OutBuffer *buf);
 
     EnumDeclaration *isEnumDeclaration() { return this; }
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
     void toDebug();
     int cvMember(unsigned char *p);
 
@@ -63,7 +77,7 @@
     EnumMember(Loc loc, Identifier *id, Expression *value);
     Dsymbol *syntaxCopy(Dsymbol *s);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
 
     void emitComment(Scope *sc);
     void toDocBuffer(OutBuffer *buf);
--- a/dmd/expression.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/expression.c	Sat Jul 12 19:38:31 2008 +0200
@@ -111,6 +111,9 @@
     precedence[TOKassert] = PREC_primary;
     precedence[TOKfunction] = PREC_primary;
     precedence[TOKvar] = PREC_primary;
+#if DMDV2
+    precedence[TOKdefault] = PREC_primary;
+#endif
 
     // post
     precedence[TOKdotti] = PREC_primary;
@@ -195,6 +198,89 @@
     precedence[TOKcomma] = PREC_expr;
 }
 
+/*************************************************************
+ * 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 == Tpointer && t->nextOf()->ty == Tstruct &&
+	  ((TypeStruct *)t->nextOf())->sym == ad)
+	&&
+	!(t->ty == Tstruct &&
+	  ((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;
+}
+
 /*****************************************
  * Determine if 'this' is available.
  * If it is, return the FuncDeclaration that has it.
@@ -383,6 +469,32 @@
     }
 }
 
+/*********************************************
+ * Call copy constructor for struct value argument.
+ */
+#if DMDV2
+Expression *callCpCtor(Loc loc, Scope *sc, Expression *e)
+{
+    Type *tb = e->type->toBasetype();
+    assert(tb->ty == Tstruct);
+    StructDeclaration *sd = ((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(0, e));
+	Expression *ae = new DeclarationExp(loc, tmp);
+	e = new CommaExp(loc, ae, new VarExp(loc, tmp));
+	e = e->semantic(sc);
+    }
+    return e;
+}
+#endif
 
 /****************************************
  * Now that we know the exact type of the function we're calling,
@@ -432,7 +544,15 @@
             error(loc, "expected %"PRIuSIZE" arguments, not %"PRIuSIZE, nparams, nargs);
 		    break;
 		}
-		arg = p->defaultArg->copy();
+		arg = p->defaultArg;
+#if DMDV2
+		if (arg->op == TOKdefault)
+		{   DefaultInitExp *de = (DefaultInitExp *)arg;
+		    arg = de->resolve(loc, sc);
+		}
+		else
+#endif
+		    arg = arg->copy();
 		arguments->push(arg);
 		nargs++;
 	    }
@@ -572,7 +692,7 @@
 	    tb = arg->type->toBasetype();
 	    if (tb->ty == Tsarray)
 	    {	TypeSArray *ts = (TypeSArray *)tb;
-		Type *ta = tb->next->arrayOf();
+		Type *ta = ts->next->arrayOf();
 		if (ts->size(arg->loc) == 0)
 		{   arg = new NullExp(arg->loc);
 		    arg->type = ta;
@@ -580,7 +700,19 @@
 		else
 		    arg = arg->castTo(sc, ta);
 	    }
-
+#if DMDV2
+	    if (tb->ty == Tstruct)
+	    {
+		arg = callCpCtor(loc, sc, arg);
+	    }
+
+	    // Give error for overloaded function addresses
+	    if (arg->op == TOKsymoff)
+	    {	SymOffExp *se = (SymOffExp *)arg;
+		if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique())
+		    arg->error("function %s is overloaded", arg->toChars());
+	    }
+#endif
 	    arg->rvalue();
 	}
 	arg = arg->optimize(WANTvalue);
@@ -609,6 +741,7 @@
 
 void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr)
 {
+    //if (precedence[e->op] == 0) e->dump(0);
     if (precedence[e->op] < pr)
     {
 	buf->writeByte('(');
@@ -706,7 +839,7 @@
 Expression *Expression::semantic(Scope *sc)
 {
 #if LOGSEMANTIC
-    printf("Expression::semantic()\n");
+    printf("Expression::semantic() %s\n", toChars());
 #endif
     if (type)
 	type = type->semantic(loc, sc);
@@ -747,6 +880,7 @@
 	dump(0);
 	halt();
 #endif
+	type = Type::tint32;
     }
 }
 
@@ -939,7 +1073,7 @@
 	    e = new NullExp(loc);
 	else
 	    e = new AddrExp(loc, this);
-	e->type = tb->next->pointerTo();
+	e->type = ts->next->pointerTo();
     }
     return e;
 }
@@ -970,7 +1104,7 @@
     {	Expression *e;
 
 	e = new PtrExp(loc, this);
-	e->type = type->next;
+	e->type = ((TypeReference *)type)->next;
 	return e;
     }
     return this;
@@ -994,6 +1128,18 @@
     return FALSE;
 }
 
+/********************************
+ * Can this expression throw an exception?
+ * Valid only after semantic() pass.
+ */
+
+int Expression::canThrow()
+{
+    return TRUE;
+}
+
+
+
 Expressions *Expression::arraySyntaxCopy(Expressions *exps)
 {   Expressions *a = NULL;
 
@@ -1019,6 +1165,7 @@
     //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
     if (type && !type->isscalar())
     {
+	//printf("%s, loc = %d\n", toChars(), loc.linnum);
 	error("integral constant must be scalar type, not %s", type->toChars());
 	type = Type::terror;
     }
@@ -1093,9 +1240,13 @@
 	    }
 
 	    default:
-		print();
-		type->print();
-		assert(0);
+		/* This can happen if errors, such as
+		 * the type is painted on like in fromConstInitializer().
+		 */
+		if (!global.errors)
+		{   type->print();
+		    assert(0);
+		}
 		break;
 	}
 	break;
@@ -1246,10 +1397,17 @@
 		goto L3;
 
 	    default:
+		/* This can happen if errors, such as
+		 * the type is painted on like in fromConstInitializer().
+		 */
+		if (!global.errors)
+		{
 #ifdef DEBUG
-		t->print();
+		    t->print();
 #endif
-		assert(0);
+		    assert(0);
+		}
+		break;
 	}
     }
     else if (v & 0x8000000000000000LL)
@@ -1993,7 +2151,8 @@
 	fd->nestedFrameRef = 1;
     }
 #endif
-    sc->callSuper |= CSXthis;
+    if (!sc->intypeof)
+	sc->callSuper |= CSXthis;
     return this;
 
 Lerr:
@@ -2102,7 +2261,8 @@
     }
 #endif
 
-    sc->callSuper |= CSXsuper;
+    if (!sc->intypeof)
+	sc->callSuper |= CSXsuper;
     return this;
 
 
@@ -3396,6 +3556,7 @@
 {
 #if LOGSEMANTIC
     printf("NewAnonClassExp::semantic() %s\n", toChars());
+    //printf("thisexp = %p\n", thisexp);
     //printf("type: %s\n", type->toChars());
 #endif
 
@@ -3982,6 +4143,8 @@
 #endif
     typeidType = typeidType->semantic(loc, sc);
     e = typeidType->getTypeInfo(sc);
+    if (e->loc.linnum == 0)
+	e->loc = loc;		// so there's at least some line number info
     return e;
 }
 
@@ -4258,7 +4421,7 @@
 	    buf->writestring(" == ");
 	tspec->toCBuffer(buf, NULL, hgs);
     }
-#if V2
+#if DMDV2
     if (parameters)
     {	// First parameter is already output, so start with second
 	for (int i = 1; i < parameters->dim; i++)
@@ -4830,6 +4993,16 @@
 		return new TypeExp(loc, t);
 	    }
 
+	    TupleDeclaration *tup = s->isTupleDeclaration();
+	    if (tup)
+	    {
+		if (eleft)
+		    error("cannot have e.tuple");
+		e = new TupleExp(loc, tup);
+		e = e->semantic(sc);
+		return e;
+	    }
+
 	    ScopeDsymbol *sds = s->isScopeDsymbol();
 	    if (sds)
 	    {
@@ -4973,55 +5146,19 @@
 	if (!var->isFuncDeclaration())	// for functions, do checks after overload resolution
 	{
 	    AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration();
-	L1:
-	    Type *t = e1->type->toBasetype();
-
-	    if (ad &&
-		!(t->ty == Tpointer && t->next->ty == Tstruct &&
-		  ((TypeStruct *)t->next)->sym == ad)
-		&&
-		!(t->ty == Tstruct &&
-		  ((TypeStruct *)t)->sym == ad)
-	       )
-	    {
-		ClassDeclaration *cd = ad->isClassDeclaration();
-		ClassDeclaration *tcd = t->isClassHandle();
-
-		if (!cd || !tcd ||
-		    !(tcd == cd || cd->isBaseOf(tcd, NULL))
-		   )
-		{
-		    if (tcd && tcd->isNested())
-		    {	// Try again with outer scope
-
-			e1 = new DotVarExp(loc, e1, tcd->vthis);
-			e1 = e1->semantic(sc);
-
-			// Skip over nested functions, and get the enclosing
-			// class type.
-			Dsymbol *s = tcd->toParent();
-			while (s && s->isFuncDeclaration())
-			{   FuncDeclaration *f = s->isFuncDeclaration();
-			    if (f->vthis)
-			    {
-				e1 = new VarExp(loc, f->vthis);
-			    }
-			    s = s->toParent();
-			}
-			if (s && s->isClassDeclaration())
-			    e1->type = s->isClassDeclaration()->type;
-
-			e1 = e1->semantic(sc);
-			goto L1;
-		    }
-#ifdef DEBUG
-		    printf("2: ");
-#endif
-		    error("this for %s needs to be type %s not type %s",
-			var->toChars(), ad->toChars(), t->toChars());
+	    e1 = getRightThis(loc, sc, ad, e1, var);
+	    if (!sc->noaccesscheck)
+		accessCheck(loc, sc, e1, var);
+
+	    VarDeclaration *v = var->isVarDeclaration();
+	    if (v && v->isConst())
+	    {	ExpInitializer *ei = v->getExpInitializer();
+		if (ei)
+		{   Expression *e = ei->exp->copy();
+		    e = e->semantic(sc);
+		    return e;
 		}
 	    }
-	    accessCheck(loc, sc, e1, var);
 	}
     }
     //printf("-DotVarExp::semantic('%s')\n", toChars());
@@ -5211,7 +5348,7 @@
     return e;
 
 Lerr:
-    return new IntegerExp(0);
+    return new IntegerExp(loc, 0, Type::tint32);
 }
 
 void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
@@ -5239,44 +5376,9 @@
 	e1 = e1->semantic(sc);
 	type = new TypeDelegate(func->type);
 	type = type->semantic(loc, sc);
-//-----------------
-	/* For func, we need to get the
-	 * right 'this' pointer if func is in an outer class, but our
-	 * existing 'this' pointer is in an inner class.
-	 * This code is analogous to that used for variables
-	 * in DotVarExp::semantic().
-	 */
 	AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration();
-    L10:
-	Type *t = e1->type;
-	if (func->needThis() && ad &&
-	    !(t->ty == Tpointer && t->next->ty == Tstruct &&
-	      ((TypeStruct *)t->next)->sym == ad) &&
-	    !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad)
-	   )
-	{
-	    ClassDeclaration *cd = ad->isClassDeclaration();
-	    ClassDeclaration *tcd = t->isClassHandle();
-
-	    if (!cd || !tcd ||
-		!(tcd == cd || cd->isBaseOf(tcd, NULL))
-	       )
-	    {
-		if (tcd && tcd->isNested())
-		{   // Try again with outer scope
-
-		    e1 = new DotVarExp(loc, e1, tcd->vthis);
-		    e1 = e1->semantic(sc);
-		    goto L10;
-		}
-#ifdef DEBUG
-		printf("3: ");
-#endif
-		error("this for %s needs to be type %s not type %s",
-		    func->toChars(), ad->toChars(), t->toChars());
-	    }
-	}
-//-----------------
+	if (func->needThis())
+	    e1 = getRightThis(loc, sc, ad, e1, func);
     }
     return this;
 }
@@ -5535,7 +5637,7 @@
 	DotTemplateExp *dte;
 	AggregateDeclaration *ad;
 	UnaExp *ue = (UnaExp *)(e1);
-        
+
     	if (e1->op == TOKdotvar)
         {   // Do overload resolution
 	    dve = (DotVarExp *)(e1);
@@ -5560,40 +5662,20 @@
 	    }
 	    ad = td->toParent()->isAggregateDeclaration();
 	}	
-	/* Now that we have the right function f, we need to get the
-	 * right 'this' pointer if f is in an outer class, but our
-	 * existing 'this' pointer is in an inner class.
-	 * This code is analogous to that used for variables
-	 * in DotVarExp::semantic().
+	if (f->needThis())
+	{
+	    ue->e1 = getRightThis(loc, sc, ad, ue->e1, f);
+	}
+
+	/* Cannot call public functions from inside invariant
+	 * (because then the invariant would have infinite recursion)
 	 */
-    L10:
-	Type *t = ue->e1->type->toBasetype();
-	if (f->needThis() && ad &&
-	    !(t->ty == Tpointer && t->next->ty == Tstruct &&
-	      ((TypeStruct *)t->next)->sym == ad) &&
-	    !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad)
+	if (sc->func && sc->func->isInvariantDeclaration() &&
+	    ue->e1->op == TOKthis &&
+	    f->addPostInvariant()
 	   )
 	{
-	    ClassDeclaration *cd = ad->isClassDeclaration();
-	    ClassDeclaration *tcd = t->isClassHandle();
-
-	    if (!cd || !tcd ||
-		!(tcd == cd || cd->isBaseOf(tcd, NULL))
-	       )
-	    {
-		if (tcd && tcd->isNested())
-		{   // Try again with outer scope
-
-		    ue->e1 = new DotVarExp(loc, ue->e1, tcd->vthis);
-		    ue->e1 = ue->e1->semantic(sc);
-		    goto L10;
-		}
-#ifdef DEBUG
-		printf("1: ");
-#endif
-		error("this for %s needs to be type %s not type %s",
-		    f->toChars(), ad->toChars(), t->toChars());
-	    }
+	    error("cannot call public/export function %s from invariant", f->toChars());
 	}
 
 	checkDeprecated(sc, f);
@@ -5647,15 +5729,18 @@
 	    }
 	    else
 	    {
+		if (!sc->intypeof)
+		{
 #if 0
-		if (sc->callSuper & (CSXthis | CSXsuper))
-		    error("reference to this before super()");
+		    if (sc->callSuper & (CSXthis | CSXsuper))
+			error("reference to this before super()");
 #endif
-		if (sc->noctor || sc->callSuper & CSXlabel)
-		    error("constructor calls not allowed in loops or after labels");
-		if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
-		    error("multiple constructor calls");
-		sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
+		    if (sc->noctor || sc->callSuper & CSXlabel)
+			error("constructor calls not allowed in loops or after labels");
+		    if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+			error("multiple constructor calls");
+		    sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
+		}
 
 		f = f->overloadResolve(loc, arguments);
 		checkDeprecated(sc, f);
@@ -5680,15 +5765,18 @@
 	}
 	else
 	{
+	    if (!sc->intypeof)
+	    {
 #if 0
-	    if (sc->callSuper & (CSXthis | CSXsuper))
-		error("reference to this before super()");
+		if (sc->callSuper & (CSXthis | CSXsuper))
+		    error("reference to this before super()");
 #endif
-	    if (sc->noctor || sc->callSuper & CSXlabel)
-		error("constructor calls not allowed in loops or after labels");
-	    if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
-		error("multiple constructor calls");
-	    sc->callSuper |= CSXany_ctor | CSXthis_ctor;
+		if (sc->noctor || sc->callSuper & CSXlabel)
+		    error("constructor calls not allowed in loops or after labels");
+		if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+		    error("multiple constructor calls");
+		sc->callSuper |= CSXany_ctor | CSXthis_ctor;
+	    }
 
 	    f = cd->ctor;
 	    f = f->overloadResolve(loc, arguments);
--- a/dmd/expression.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/expression.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -140,6 +140,7 @@
     virtual int isBool(int result);
     virtual int isBit();
     virtual int checkSideEffect(int flag);
+    virtual int canThrow();
 
     virtual int inlineCost(InlineCostState *ics);
     virtual Expression *doInline(InlineDoState *ids);
--- a/dmd/func.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/func.c	Sat Jul 12 19:38:31 2008 +0200
@@ -103,6 +103,7 @@
     StructDeclaration *sd;
     ClassDeclaration *cd;
     InterfaceDeclaration *id;
+    Dsymbol *pd;
 
 #if 0
     printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage);
@@ -208,6 +209,18 @@
 	    error("function body is not abstract in interface %s", id->toChars());
     }
 
+    /* Template member functions aren't virtual:
+     *   interface TestInterface { void tpl(T)(); }
+     * and so won't work in interfaces
+     */
+    if ((pd = toParent()) != NULL &&
+	pd->isTemplateInstance() &&
+	(pd = toParent2()) != NULL &&
+	(id = pd->isInterfaceDeclaration()) != NULL)
+    {
+	error("template member function not allowed in interface %s", id->toChars());
+    }
+
     cd = parent->isClassDeclaration();
     if (cd)
     {	int vi;
@@ -306,7 +319,7 @@
 		if (fdv->isFinal())
 		    error("cannot override final function %s", fdv->toPrettyChars());
 
-#if V2
+#if DMDV2
 		if (!isOverride() && global.params.warnings)
 		    warning("%s: overrides base class function %s, but is not marked with 'override'", locToChars() fdv->toPrettyChars());
 #endif
@@ -322,7 +335,7 @@
 #if !BREAKABI
 			&& !isDtorDeclaration()
 #endif
-#if V2
+#if DMDV2
 			&& !isPostBlitDeclaration()
 #endif
 			)
@@ -978,7 +991,8 @@
 		f = (TypeFunction *)type;
 	    }
 
-	    int offend = fbody ? fbody->fallOffEnd() : TRUE;
+	    int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE;
+	    //int offend = fbody ? fbody->fallOffEnd() : TRUE;
 
 	    if (isStaticCtorDeclaration())
 	    {	/* It's a static constructor. Ensure that all
@@ -1471,7 +1485,7 @@
 	return 1;
     }
 
-#if V2
+#if DMDV2
     /* Allow covariant matches, if it's just a const conversion
      * of the return type
      */
@@ -1777,6 +1791,7 @@
     }
     return (LabelDsymbol *)s;
 }
+
 /****************************************
  * If non-static member function that has a 'this' pointer,
  * return the aggregate it is a member of.
@@ -2031,17 +2046,18 @@
     return fd;
 }
 
-char *FuncDeclaration::kind()
+const char *FuncDeclaration::kind()
 {
     return "function";
 }
+
 /*******************************
  * Look at all the variables in this function that are referenced
  * by nested functions, and determine if a closure needs to be
  * created for them.
  */
 
-#if V2
+#if DMDV2
 int FuncDeclaration::needsClosure()
 {
     /* Need a closure for all the closureVars[] if any of the
@@ -2051,7 +2067,11 @@
      * 1) is a virtual function
      * 2) has its address taken
      * 3) has a parent that escapes
-     * escapes.
+     *
+     * Note that since a non-virtual function can be called by
+     * a virtual one, if that non-virtual function accesses a closure
+     * var, the closure still has to be taken. Hence, we check for isThis()
+     * instead of isVirtual(). (thanks to David Friedman)
      */
 
     //printf("FuncDeclaration::needsClosure() %s\n", toChars());
@@ -2065,14 +2085,14 @@
 	    assert(f != this);
 
 	    //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf);
-	    if (f->isVirtual() || f->tookAddressOf)
+	    if (f->isThis() || f->tookAddressOf)
 		goto Lyes;	// assume f escapes this function's scope
 
 	    // Look to see if any parents of f that are below this escape
 	    for (Dsymbol *s = f->parent; s != this; s = s->parent)
 	    {
 		f = s->isFuncDeclaration();
-		if (f && (f->isVirtual() || f->tookAddressOf))
+		if (f && (f->isThis() || f->tookAddressOf))
 		    goto Lyes;
 	    }
 	}
@@ -2097,7 +2117,7 @@
     this->funcalias = funcalias;
 }
 
-char *FuncAliasDeclaration::kind()
+const char *FuncAliasDeclaration::kind()
 {
     return "function alias";
 }
@@ -2142,7 +2162,12 @@
     return (tok == TOKdelegate);
 }
 
-char *FuncLiteralDeclaration::kind()
+int FuncLiteralDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+const char *FuncLiteralDeclaration::kind()
 {
     // GCC requires the (char*) casts
     return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function";
@@ -2214,6 +2239,8 @@
     else
 	tret = cd->type; //->referenceTo();
     type = new TypeFunction(arguments, tret, varargs, LINKd);
+    if (!originalType)
+	originalType = type;
 
     sc->flags |= SCOPEctor;
     type = type->semantic(loc, sc);
@@ -2240,7 +2267,7 @@
 	cd->defaultCtor = this;
 }
 
-char *CtorDeclaration::kind()
+const char *CtorDeclaration::kind()
 {
     return "constructor";
 }
@@ -2377,6 +2404,34 @@
 
     type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
 
+    /* If the static ctor appears within a template instantiation,
+     * it could get called multiple times by the module constructors
+     * for different modules. Thus, protect it with a gate.
+     */
+    if (inTemplateInstance())
+    {
+	/* Add this prefix to the function:
+	 *	static int gate;
+	 *	if (++gate != 1) return;
+	 * Note that this is not thread safe; should not have threads
+	 * during static construction.
+	 */
+	Identifier *id = Lexer::idPool("__gate");
+	VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL);
+	v->storage_class = STCstatic;
+	Statements *sa = new Statements();
+	Statement *s = new DeclarationStatement(0, v);
+	sa->push(s);
+	Expression *e = new IdentifierExp(0, id);
+	e = new AddAssignExp(0, e, new IntegerExp(1));
+	e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1));
+	s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL);
+	sa->push(s);
+	if (fbody)
+	    sa->push(fbody);
+	fbody = new CompoundStatement(0, sa);
+    }
+
     FuncDeclaration::semantic(sc);
 
     // We're going to need ModuleInfo
@@ -2432,6 +2487,7 @@
     : FuncDeclaration(loc, endloc,
       Identifier::generateId("_staticDtor"), STCstatic, NULL)
 {
+    vgate = NULL;
 }
 
 Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
@@ -2455,6 +2511,36 @@
     }
     type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
 
+    /* If the static ctor appears within a template instantiation,
+     * it could get called multiple times by the module constructors
+     * for different modules. Thus, protect it with a gate.
+     */
+    if (inTemplateInstance())
+    {
+	/* Add this prefix to the function:
+	 *	static int gate;
+	 *	if (--gate != 0) return;
+	 * Increment gate during constructor execution.
+	 * Note that this is not thread safe; should not have threads
+	 * during static destruction.
+	 */
+	Identifier *id = Lexer::idPool("__gate");
+	VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL);
+	v->storage_class = STCstatic;
+	Statements *sa = new Statements();
+	Statement *s = new DeclarationStatement(0, v);
+	sa->push(s);
+	Expression *e = new IdentifierExp(0, id);
+	e = new AddAssignExp(0, e, new IntegerExp(-1));
+	e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1));
+	s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL);
+	sa->push(s);
+	if (fbody)
+	    sa->push(fbody);
+	fbody = new CompoundStatement(0, sa);
+	vgate = v;
+    }
+
     FuncDeclaration::semantic(sc);
 
     // We're going to need ModuleInfo
@@ -2583,12 +2669,7 @@
 
 static Identifier *unitTestId()
 {
-    static int n;
-    char buffer[10 + sizeof(n)*3 + 1];
-
-    sprintf(buffer,"__unittest%d", n);
-    n++;
-    return Lexer::idPool(buffer);
+    return Lexer::uniqueId("__unittest");
 }
 
 UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc)
@@ -2713,7 +2794,7 @@
     FuncDeclaration::semantic(sc);
 }
 
-char *NewDeclaration::kind()
+const char *NewDeclaration::kind()
 {
     return "allocator";
 }
@@ -2797,7 +2878,7 @@
     FuncDeclaration::semantic(sc);
 }
 
-char *DeleteDeclaration::kind()
+const char *DeleteDeclaration::kind()
 {
     return "deallocator";
 }
--- a/dmd/id.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/id.c	Sat Jul 12 19:38:31 2008 +0200
@@ -40,6 +40,8 @@
 Identifier *Id::empty;
 Identifier *Id::p;
 Identifier *Id::coverage;
+Identifier *Id::__vptr;
+Identifier *Id::__monitor;
 Identifier *Id::TypeInfo;
 Identifier *Id::TypeInfo_Class;
 Identifier *Id::TypeInfo_Interface;
@@ -213,6 +215,8 @@
     empty = Lexer::idPool("");
     p = Lexer::idPool("p");
     coverage = Lexer::idPool("__coverage");
+    __vptr = Lexer::idPool("__vptr");
+    __monitor = Lexer::idPool("__monitor");
     TypeInfo = Lexer::idPool("TypeInfo");
     TypeInfo_Class = Lexer::idPool("TypeInfo_Class");
     TypeInfo_Interface = Lexer::idPool("TypeInfo_Interface");
--- a/dmd/id.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/id.h	Sat Jul 12 19:38:31 2008 +0200
@@ -42,6 +42,8 @@
     static Identifier *empty;
     static Identifier *p;
     static Identifier *coverage;
+    static Identifier *__vptr;
+    static Identifier *__monitor;
     static Identifier *TypeInfo;
     static Identifier *TypeInfo_Class;
     static Identifier *TypeInfo_Interface;
--- a/dmd/idgen.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/idgen.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,302 +1,304 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-// Program to generate string files in d data structures.
-// Saves much tedious typing, and eliminates typo problems.
-// Generates:
-//	id.h
-//	id.c
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <assert.h>
-
-struct Msgtable
-{
-	char *ident;	// name to use in DMD source
-	char *name;	// name in D executable
-};
-
-Msgtable msgtable[] =
-{
-    { "IUnknown" },
-    { "Object" },
-    { "object" },
-    { "max" },
-    { "min" },
-    { "This", "this" },
-    { "ctor", "_ctor" },
-    { "dtor", "_dtor" },
-    { "classInvariant", "__invariant" },
-    { "unitTest", "_unitTest" },
-    { "init" },
-    { "size" },
-    { "__sizeof", "sizeof" },
-    { "alignof" },
-    { "mangleof" },
-    { "stringof" },
-    { "tupleof" },
-    { "length" },
-    { "remove" },
-    { "ptr" },
-    { "funcptr" },
-    { "dollar", "__dollar" },
-    { "offset" },
-    { "offsetof" },
-    { "ModuleInfo" },
-    { "ClassInfo" },
-    { "classinfo" },
-    { "typeinfo" },
-    { "outer" },
-    { "Exception" },
-    { "withSym", "__withSym" },
-    { "result", "__result" },
-    { "returnLabel", "__returnLabel" },
-    { "delegate" },
-    { "line" },
-    { "empty", "" },
-    { "p" },
-    { "coverage", "__coverage" },
-
-    { "TypeInfo" },
-    { "TypeInfo_Class" },
-    { "TypeInfo_Interface" },
-    { "TypeInfo_Struct" },
-    { "TypeInfo_Enum" },
-    { "TypeInfo_Typedef" },
-    { "TypeInfo_Pointer" },
-    { "TypeInfo_Array" },
-    { "TypeInfo_StaticArray" },
-    { "TypeInfo_AssociativeArray" },
-    { "TypeInfo_Function" },
-    { "TypeInfo_Delegate" },
-    { "TypeInfo_Tuple" },
-    { "TypeInfo_Const" },
-    { "TypeInfo_Invariant" },
-    { "elements" },
-    { "_arguments_typeinfo" },
-    { "_arguments" },
-    { "_argptr" },
-    { "_match" },
-
-    { "LINE", "__LINE__" },
-    { "FILE", "__FILE__" },
-    { "DATE", "__DATE__" },
-    { "TIME", "__TIME__" },
-    { "TIMESTAMP", "__TIMESTAMP__" },
-    { "VENDOR", "__VENDOR__" },
-    { "VERSIONX", "__VERSION__" },
-
-    { "nan" },
-    { "infinity" },
-    { "dig" },
-    { "epsilon" },
-    { "mant_dig" },
-    { "max_10_exp" },
-    { "max_exp" },
-    { "min_10_exp" },
-    { "min_exp" },
-    { "re" },
-    { "im" },
-
-    { "C" },
-    { "D" },
-    { "Windows" },
-    { "Pascal" },
-    { "System" },
-
-    { "exit" },
-    { "success" },
-    { "failure" },
-
-    { "keys" },
-    { "values" },
-    { "rehash" },
-
-    { "sort" },
-    { "reverse" },
-    { "dup" },
-    { "idup" },
-
-    // For inline assembler
-    { "___out", "out" },
-    { "___in", "in" },
-    { "__int", "int" },
-    { "__dollar", "$" },
-    { "__LOCAL_SIZE" },
-
-    // For operator overloads
-    { "uadd",	 "opPos" },
-    { "neg",     "opNeg" },
-    { "com",     "opCom" },
-    { "add",     "opAdd" },
-    { "add_r",   "opAdd_r" },
-    { "sub",     "opSub" },
-    { "sub_r",   "opSub_r" },
-    { "mul",     "opMul" },
-    { "mul_r",   "opMul_r" },
-    { "div",     "opDiv" },
-    { "div_r",   "opDiv_r" },
-    { "mod",     "opMod" },
-    { "mod_r",   "opMod_r" },
-    { "eq",      "opEquals" },
-    { "cmp",     "opCmp" },
-    { "iand",    "opAnd" },
-    { "iand_r",  "opAnd_r" },
-    { "ior",     "opOr" },
-    { "ior_r",   "opOr_r" },
-    { "ixor",    "opXor" },
-    { "ixor_r",  "opXor_r" },
-    { "shl",     "opShl" },
-    { "shl_r",   "opShl_r" },
-    { "shr",     "opShr" },
-    { "shr_r",   "opShr_r" },
-    { "ushr",    "opUShr" },
-    { "ushr_r",  "opUShr_r" },
-    { "cat",     "opCat" },
-    { "cat_r",   "opCat_r" },
-    { "assign",  "opAssign" },
-    { "addass",  "opAddAssign" },
-    { "subass",  "opSubAssign" },
-    { "mulass",  "opMulAssign" },
-    { "divass",  "opDivAssign" },
-    { "modass",  "opModAssign" },
-    { "andass",  "opAndAssign" },
-    { "orass",   "opOrAssign" },
-    { "xorass",  "opXorAssign" },
-    { "shlass",  "opShlAssign" },
-    { "shrass",  "opShrAssign" },
-    { "ushrass", "opUShrAssign" },
-    { "catass",  "opCatAssign" },
-    { "postinc", "opPostInc" },
-    { "postdec", "opPostDec" },
-    { "index",	 "opIndex" },
-    { "indexass", "opIndexAssign" },
-    { "slice",	 "opSlice" },
-    { "sliceass", "opSliceAssign" },
-    { "call",	 "opCall" },
-    { "cast",	 "opCast" },
-    { "match",	 "opMatch" },
-    { "next",	 "opNext" },
-    { "opIn" },
-    { "opIn_r" },
-
-    { "classNew", "new" },
-    { "classDelete", "delete" },
-
-    // For foreach
-    { "apply", "opApply" },
-    { "applyReverse", "opApplyReverse" },
-
-    { "adDup", "_adDupT" },
-    { "adReverse", "_adReverse" },
-
-    // For internal functions
-    { "aaLen", "_aaLen" },
-    { "aaKeys", "_aaKeys" },
-    { "aaValues", "_aaValues" },
-    { "aaRehash", "_aaRehash" },
-
-    // For pragma's
-    { "lib" },
-    { "msg" },
-    { "GNU_asm" },
-    { "LLVM_intrinsic" },
-    { "LLVM_internal" },
-
-    // For toHash/toString
-    { "tohash", "toHash" },
-    { "tostring", "toString" },
-
-    // Special functions
-    { "alloca" },
-    { "main" },
-    { "WinMain" },
-    { "DllMain" },
-};
-
-
-int main()
-{
-    FILE *fp;
-    unsigned i;
-
-    {
-	fp = fopen("id.h","w");
-	if (!fp)
-	{   printf("can't open id.h\n");
-	    exit(EXIT_FAILURE);
-	}
-
-	fprintf(fp, "// File generated by idgen.c\n");
-#if __DMC__
-	fprintf(fp, "#pragma once\n");
-#endif
-	fprintf(fp, "#ifndef DMD_ID_H\n");
-	fprintf(fp, "#define DMD_ID_H 1\n");
-	fprintf(fp, "struct Identifier;\n");
-	fprintf(fp, "struct Id\n");
-	fprintf(fp, "{\n");
-
-	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
-	{   char *id = msgtable[i].ident;
-
-	    fprintf(fp,"    static Identifier *%s;\n", id);
-	}
-
-	fprintf(fp, "    static void initialize();\n");
-	fprintf(fp, "};\n");
-	fprintf(fp, "#endif\n");
-
-	fclose(fp);
-    }
-
-    {
-	fp = fopen("id.c","w");
-	if (!fp)
-	{   printf("can't open id.c\n");
-	    exit(EXIT_FAILURE);
-	}
-
-	fprintf(fp, "// File generated by idgen.c\n");
-	fprintf(fp, "#include \"id.h\"\n");
-	fprintf(fp, "#include \"identifier.h\"\n");
-	fprintf(fp, "#include \"lexer.h\"\n");
-
-	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
-	{   char *id = msgtable[i].ident;
-	    char *p = msgtable[i].name;
-
-	    if (!p)
-		p = id;
-	    fprintf(fp,"Identifier *Id::%s;\n", id);
-	}
-
-	fprintf(fp, "void Id::initialize()\n");
-	fprintf(fp, "{\n");
-
-	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
-	{   char *id = msgtable[i].ident;
-	    char *p = msgtable[i].name;
-
-	    if (!p)
-		p = id;
-	    fprintf(fp,"    %s = Lexer::idPool(\"%s\");\n", id, p);
-	}
-
-	fprintf(fp, "}\n");
-
-	fclose(fp);
-    }
-
-    return EXIT_SUCCESS;
-}
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Program to generate string files in d data structures.
+// Saves much tedious typing, and eliminates typo problems.
+// Generates:
+//	id.h
+//	id.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+struct Msgtable
+{
+	char *ident;	// name to use in DMD source
+	char *name;	// name in D executable
+};
+
+Msgtable msgtable[] =
+{
+    { "IUnknown" },
+    { "Object" },
+    { "object" },
+    { "max" },
+    { "min" },
+    { "This", "this" },
+    { "ctor", "_ctor" },
+    { "dtor", "_dtor" },
+    { "classInvariant", "__invariant" },
+    { "unitTest", "_unitTest" },
+    { "init" },
+    { "size" },
+    { "__sizeof", "sizeof" },
+    { "alignof" },
+    { "mangleof" },
+    { "stringof" },
+    { "tupleof" },
+    { "length" },
+    { "remove" },
+    { "ptr" },
+    { "funcptr" },
+    { "dollar", "__dollar" },
+    { "offset" },
+    { "offsetof" },
+    { "ModuleInfo" },
+    { "ClassInfo" },
+    { "classinfo" },
+    { "typeinfo" },
+    { "outer" },
+    { "Exception" },
+    { "withSym", "__withSym" },
+    { "result", "__result" },
+    { "returnLabel", "__returnLabel" },
+    { "delegate" },
+    { "line" },
+    { "empty", "" },
+    { "p" },
+    { "coverage", "__coverage" },
+    { "__vptr" },
+    { "__monitor" },
+
+    { "TypeInfo" },
+    { "TypeInfo_Class" },
+    { "TypeInfo_Interface" },
+    { "TypeInfo_Struct" },
+    { "TypeInfo_Enum" },
+    { "TypeInfo_Typedef" },
+    { "TypeInfo_Pointer" },
+    { "TypeInfo_Array" },
+    { "TypeInfo_StaticArray" },
+    { "TypeInfo_AssociativeArray" },
+    { "TypeInfo_Function" },
+    { "TypeInfo_Delegate" },
+    { "TypeInfo_Tuple" },
+    { "TypeInfo_Const" },
+    { "TypeInfo_Invariant" },
+    { "elements" },
+    { "_arguments_typeinfo" },
+    { "_arguments" },
+    { "_argptr" },
+    { "_match" },
+
+    { "LINE", "__LINE__" },
+    { "FILE", "__FILE__" },
+    { "DATE", "__DATE__" },
+    { "TIME", "__TIME__" },
+    { "TIMESTAMP", "__TIMESTAMP__" },
+    { "VENDOR", "__VENDOR__" },
+    { "VERSIONX", "__VERSION__" },
+
+    { "nan" },
+    { "infinity" },
+    { "dig" },
+    { "epsilon" },
+    { "mant_dig" },
+    { "max_10_exp" },
+    { "max_exp" },
+    { "min_10_exp" },
+    { "min_exp" },
+    { "re" },
+    { "im" },
+
+    { "C" },
+    { "D" },
+    { "Windows" },
+    { "Pascal" },
+    { "System" },
+
+    { "exit" },
+    { "success" },
+    { "failure" },
+
+    { "keys" },
+    { "values" },
+    { "rehash" },
+
+    { "sort" },
+    { "reverse" },
+    { "dup" },
+    { "idup" },
+
+    // For inline assembler
+    { "___out", "out" },
+    { "___in", "in" },
+    { "__int", "int" },
+    { "__dollar", "$" },
+    { "__LOCAL_SIZE" },
+
+    // For operator overloads
+    { "uadd",	 "opPos" },
+    { "neg",     "opNeg" },
+    { "com",     "opCom" },
+    { "add",     "opAdd" },
+    { "add_r",   "opAdd_r" },
+    { "sub",     "opSub" },
+    { "sub_r",   "opSub_r" },
+    { "mul",     "opMul" },
+    { "mul_r",   "opMul_r" },
+    { "div",     "opDiv" },
+    { "div_r",   "opDiv_r" },
+    { "mod",     "opMod" },
+    { "mod_r",   "opMod_r" },
+    { "eq",      "opEquals" },
+    { "cmp",     "opCmp" },
+    { "iand",    "opAnd" },
+    { "iand_r",  "opAnd_r" },
+    { "ior",     "opOr" },
+    { "ior_r",   "opOr_r" },
+    { "ixor",    "opXor" },
+    { "ixor_r",  "opXor_r" },
+    { "shl",     "opShl" },
+    { "shl_r",   "opShl_r" },
+    { "shr",     "opShr" },
+    { "shr_r",   "opShr_r" },
+    { "ushr",    "opUShr" },
+    { "ushr_r",  "opUShr_r" },
+    { "cat",     "opCat" },
+    { "cat_r",   "opCat_r" },
+    { "assign",  "opAssign" },
+    { "addass",  "opAddAssign" },
+    { "subass",  "opSubAssign" },
+    { "mulass",  "opMulAssign" },
+    { "divass",  "opDivAssign" },
+    { "modass",  "opModAssign" },
+    { "andass",  "opAndAssign" },
+    { "orass",   "opOrAssign" },
+    { "xorass",  "opXorAssign" },
+    { "shlass",  "opShlAssign" },
+    { "shrass",  "opShrAssign" },
+    { "ushrass", "opUShrAssign" },
+    { "catass",  "opCatAssign" },
+    { "postinc", "opPostInc" },
+    { "postdec", "opPostDec" },
+    { "index",	 "opIndex" },
+    { "indexass", "opIndexAssign" },
+    { "slice",	 "opSlice" },
+    { "sliceass", "opSliceAssign" },
+    { "call",	 "opCall" },
+    { "cast",	 "opCast" },
+    { "match",	 "opMatch" },
+    { "next",	 "opNext" },
+    { "opIn" },
+    { "opIn_r" },
+
+    { "classNew", "new" },
+    { "classDelete", "delete" },
+
+    // For foreach
+    { "apply", "opApply" },
+    { "applyReverse", "opApplyReverse" },
+
+    { "adDup", "_adDupT" },
+    { "adReverse", "_adReverse" },
+
+    // For internal functions
+    { "aaLen", "_aaLen" },
+    { "aaKeys", "_aaKeys" },
+    { "aaValues", "_aaValues" },
+    { "aaRehash", "_aaRehash" },
+
+    // For pragma's
+    { "lib" },
+    { "msg" },
+    { "GNU_asm" },
+    { "LLVM_intrinsic" },
+    { "LLVM_internal" },
+
+    // For toHash/toString
+    { "tohash", "toHash" },
+    { "tostring", "toString" },
+
+    // Special functions
+    { "alloca" },
+    { "main" },
+    { "WinMain" },
+    { "DllMain" },
+};
+
+
+int main()
+{
+    FILE *fp;
+    unsigned i;
+
+    {
+	fp = fopen("id.h","w");
+	if (!fp)
+	{   printf("can't open id.h\n");
+	    exit(EXIT_FAILURE);
+	}
+
+	fprintf(fp, "// File generated by idgen.c\n");
+#if __DMC__
+	fprintf(fp, "#pragma once\n");
+#endif
+	fprintf(fp, "#ifndef DMD_ID_H\n");
+	fprintf(fp, "#define DMD_ID_H 1\n");
+	fprintf(fp, "struct Identifier;\n");
+	fprintf(fp, "struct Id\n");
+	fprintf(fp, "{\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+
+	    fprintf(fp,"    static Identifier *%s;\n", id);
+	}
+
+	fprintf(fp, "    static void initialize();\n");
+	fprintf(fp, "};\n");
+	fprintf(fp, "#endif\n");
+
+	fclose(fp);
+    }
+
+    {
+	fp = fopen("id.c","w");
+	if (!fp)
+	{   printf("can't open id.c\n");
+	    exit(EXIT_FAILURE);
+	}
+
+	fprintf(fp, "// File generated by idgen.c\n");
+	fprintf(fp, "#include \"id.h\"\n");
+	fprintf(fp, "#include \"identifier.h\"\n");
+	fprintf(fp, "#include \"lexer.h\"\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+	    char *p = msgtable[i].name;
+
+	    if (!p)
+		p = id;
+	    fprintf(fp,"Identifier *Id::%s;\n", id);
+	}
+
+	fprintf(fp, "void Id::initialize()\n");
+	fprintf(fp, "{\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+	    char *p = msgtable[i].name;
+
+	    if (!p)
+		p = id;
+	    fprintf(fp,"    %s = Lexer::idPool(\"%s\");\n", id, p);
+	}
+
+	fprintf(fp, "}\n");
+
+	fclose(fp);
+    }
+
+    return EXIT_SUCCESS;
+}
--- a/dmd/import.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/import.c	Sat Jul 12 19:38:31 2008 +0200
@@ -55,7 +55,7 @@
     aliases.push(alias);
 }
 
-char *Import::kind()
+const char *Import::kind()
 {
     return isstatic ? (char *)"static import" : (char *)"import";
 }
--- a/dmd/import.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/import.h	Sat Jul 12 19:38:31 2008 +0200
@@ -48,7 +48,7 @@
 	int isstatic);
     void addAlias(Identifier *name, Identifier *alias);
 
-    char *kind();
+    const char *kind();
     Dsymbol *syntaxCopy(Dsymbol *s);	// copy only syntax trees
     void load(Scope *sc);
     void semantic(Scope *sc);
--- a/dmd/init.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/init.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,584 +1,586 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "statement.h"
-#include "identifier.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "hdrgen.h"
-
-/********************************** Initializer *******************************/
-
-Initializer::Initializer(Loc loc)
-{
-    this->loc = loc;
-}
-
-Initializer *Initializer::syntaxCopy()
-{
-    return this;
-}
-
-Initializer *Initializer::semantic(Scope *sc, Type *t)
-{
-    return this;
-}
-
-Type *Initializer::inferType(Scope *sc)
-{
-    error(loc, "cannot infer type from initializer");
-    return Type::terror;
-}
-
-Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
-{   Initializers *a = NULL;
-
-    if (ai)
-    {
-	a = new Initializers();
-	a->setDim(ai->dim);
-	for (int i = 0; i < a->dim; i++)
-	{   Initializer *e = (Initializer *)ai->data[i];
-
-	    e = e->syntaxCopy();
-	    a->data[i] = e;
-	}
-    }
-    return a;
-}
-
-char *Initializer::toChars()
-{   OutBuffer *buf;
-    HdrGenState hgs;
-
-    memset(&hgs, 0, sizeof(hgs));
-    buf = new OutBuffer();
-    toCBuffer(buf, &hgs);
-    return buf->toChars();
-}
-
-/********************************** VoidInitializer ***************************/
-
-VoidInitializer::VoidInitializer(Loc loc)
-    : Initializer(loc)
-{
-    type = NULL;
-}
-
-
-Initializer *VoidInitializer::syntaxCopy()
-{
-    return new VoidInitializer(loc);
-}
-
-
-Initializer *VoidInitializer::semantic(Scope *sc, Type *t)
-{
-    //printf("VoidInitializer::semantic(t = %p)\n", t);
-    type = t;
-    return this;
-}
-
-
-Expression *VoidInitializer::toExpression()
-{
-    error(loc, "void initializer has no value");
-    return new IntegerExp(0);
-}
-
-
-void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("void");
-}
-
-
-/********************************** StructInitializer *************************/
-
-StructInitializer::StructInitializer(Loc loc)
-    : Initializer(loc)
-{
-    ad = NULL;
-}
-
-Initializer *StructInitializer::syntaxCopy()
-{
-    StructInitializer *ai = new StructInitializer(loc);
-
-    assert(field.dim == value.dim);
-    ai->field.setDim(field.dim);
-    ai->value.setDim(value.dim);
-    for (int i = 0; i < field.dim; i++)
-    {    
-	ai->field.data[i] = field.data[i];
-
-	Initializer *init = (Initializer *)value.data[i];
-	init = init->syntaxCopy();
-	ai->value.data[i] = init;
-    }
-    return ai;
-}
-
-void StructInitializer::addInit(Identifier *field, Initializer *value)
-{
-    //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
-    this->field.push(field);
-    this->value.push(value);
-}
-
-Initializer *StructInitializer::semantic(Scope *sc, Type *t)
-{
-    TypeStruct *ts;
-    int errors = 0;
-
-    //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
-    vars.setDim(field.dim);
-    t = t->toBasetype();
-    if (t->ty == Tstruct)
-    {	unsigned i;
-	unsigned fieldi = 0;
-
-	ts = (TypeStruct *)t;
-	ad = ts->sym;
-	for (i = 0; i < field.dim; i++)
-	{
-	    Identifier *id = (Identifier *)field.data[i];
-	    Initializer *val = (Initializer *)value.data[i];
-	    Dsymbol *s;
-	    VarDeclaration *v;
-
-	    if (id == NULL)
-	    {
-		if (fieldi >= ad->fields.dim)
-		{   error(loc, "too many initializers for %s", ad->toChars());
-		    continue;
-		}
-		else
-		{
-		    s = (Dsymbol *)ad->fields.data[fieldi];
-		}
-	    }
-	    else
-	    {
-		//s = ad->symtab->lookup(id);
-		s = ad->search(loc, id, 0);
-		if (!s)
-		{
-		    error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
-		    continue;
-		}
-
-		// Find out which field index it is
-		for (fieldi = 0; 1; fieldi++)
-		{
-		    if (fieldi >= ad->fields.dim)
-		    {
-			s->error("is not a per-instance initializable field");
-			break;
-		    }
-		    if (s == (Dsymbol *)ad->fields.data[fieldi])
-			break;
-		}
-	    }
-	    if (s && (v = s->isVarDeclaration()) != NULL)
-	    {
-		val = val->semantic(sc, v->type);
-		value.data[i] = (void *)val;
-		vars.data[i] = (void *)v;
-	    }
-	    else
-	    {	error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
-		errors = 1;
-	    }
-	    fieldi++;
-	}
-    }
-    else if (t->ty == Tdelegate && value.dim == 0)
-    {	/* Rewrite as empty delegate literal { }
-	 */
-	Arguments *arguments = new Arguments;
-	Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
-	FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
-	fd->fbody = new CompoundStatement(loc, new Statements());
-	fd->endloc = loc;
-	Expression *e = new FuncExp(loc, fd);
-	ExpInitializer *ie = new ExpInitializer(loc, e);
-	return ie->semantic(sc, t);
-    }
-    else
-    {
-	error(loc, "a struct is not a valid initializer for a %s", t->toChars());
-	errors = 1;
-    }
-    if (errors)
-    {
-	field.setDim(0);
-	value.setDim(0);
-	vars.setDim(0);
-    }
-    return this;
-}
-
-
-/***************************************
- * This works by transforming a struct initializer into
- * a struct literal. In the future, the two should be the
- * same thing.
- */
-Expression *StructInitializer::toExpression()
-{   Expression *e;
-
-    //printf("StructInitializer::toExpression() %s\n", toChars());
-    if (!ad)				// if fwd referenced
-    {
-	return NULL;
-    }
-    StructDeclaration *sd = ad->isStructDeclaration();
-    if (!sd)
-	return NULL;
-    Expressions *elements = new Expressions();
-    for (size_t i = 0; i < value.dim; i++)
-    {
-	if (field.data[i])
-	    goto Lno;
-	Initializer *iz = (Initializer *)value.data[i];
-	if (!iz)
-	    goto Lno;
-	Expression *ex = iz->toExpression();
-	if (!ex)
-	    goto Lno;
-	elements->push(ex);
-    }
-    e = new StructLiteralExp(loc, sd, elements);
-    e->type = sd->type;
-    return e;
-
-Lno:
-    delete elements;
-    //error(loc, "struct initializers as expressions are not allowed");
-    return NULL;
-}
-
-
-void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    //printf("StructInitializer::toCBuffer()\n");
-    buf->writebyte('{');
-    for (int i = 0; i < field.dim; i++)
-    {
-        if (i > 0)
-	    buf->writebyte(',');
-        Identifier *id = (Identifier *)field.data[i];
-        if (id)
-        {
-            buf->writestring(id->toChars());
-            buf->writebyte(':');
-        }
-        Initializer *iz = (Initializer *)value.data[i];
-        if (iz)
-            iz->toCBuffer(buf, hgs);
-    }
-    buf->writebyte('}');
-}
-
-/********************************** ArrayInitializer ************************************/
-
-ArrayInitializer::ArrayInitializer(Loc loc)
-    : Initializer(loc)
-{
-    dim = 0;
-    type = NULL;
-    sem = 0;
-}
-
-Initializer *ArrayInitializer::syntaxCopy()
-{
-    //printf("ArrayInitializer::syntaxCopy()\n");
-
-    ArrayInitializer *ai = new ArrayInitializer(loc);
-
-    assert(index.dim == value.dim);
-    ai->index.setDim(index.dim);
-    ai->value.setDim(value.dim);
-    for (int i = 0; i < ai->value.dim; i++)
-    {	Expression *e = (Expression *)index.data[i];
-	if (e)
-	    e = e->syntaxCopy();
-	ai->index.data[i] = e;
-
-	Initializer *init = (Initializer *)value.data[i];
-	init = init->syntaxCopy();
-	ai->value.data[i] = init;
-    }
-    return ai;
-}
-
-void ArrayInitializer::addInit(Expression *index, Initializer *value)
-{
-    this->index.push(index);
-    this->value.push(value);
-    dim = 0;
-    type = NULL;
-}
-
-Initializer *ArrayInitializer::semantic(Scope *sc, Type *t)
-{   unsigned i;
-    unsigned length;
-
-    //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
-    if (sem)				// if semantic() already run
-	return this;
-    sem = 1;
-    type = t;
-    t = t->toBasetype();
-    switch (t->ty)
-    {
-	case Tpointer:
-	case Tsarray:
-	case Tarray:
-	    break;
-
-	default:
-	    error(loc, "cannot use array to initialize %s", type->toChars());
-	    return this;
-    }
-
-    length = 0;
-    for (i = 0; i < index.dim; i++)
-    {	Expression *idx;
-	Initializer *val;
-
-	idx = (Expression *)index.data[i];
-	if (idx)
-	{   idx = idx->semantic(sc);
-	    idx = idx->optimize(WANTvalue | WANTinterpret);
-	    index.data[i] = (void *)idx;
-	    length = idx->toInteger();
-	}
-
-	val = (Initializer *)value.data[i];
-	val = val->semantic(sc, t->next);
-	value.data[i] = (void *)val;
-	length++;
-	if (length == 0)
-	    error("array dimension overflow");
-	if (length > dim)
-	    dim = length;
-    }
-    unsigned long amax = 0x80000000;
-    if ((unsigned long) dim * t->next->size() >= amax)
-	error(loc, "array dimension %u exceeds max of %llu", dim, amax / t->next->size());
-    return this;
-}
-
-/********************************
- * If possible, convert array initializer to array literal.
- */
-
-Expression *ArrayInitializer::toExpression()
-{   Expressions *elements;
-    Expression *e;
-
-    //printf("ArrayInitializer::toExpression()\n");
-    //static int i; if (++i == 2) halt();
-    elements = new Expressions();
-    for (size_t i = 0; i < value.dim; i++)
-    {
-	if (index.data[i])
-	    goto Lno;
-	Initializer *iz = (Initializer *)value.data[i];
-	if (!iz)
-	    goto Lno;
-	Expression *ex = iz->toExpression();
-	if (!ex)
-	    goto Lno;
-	elements->push(ex);
-    }
-    e = new ArrayLiteralExp(loc, elements);
-    e->type = type;
-    return e;
-
-Lno:
-    delete elements;
-    error(loc, "array initializers as expressions are not allowed");
-    return NULL;
-}
-
-
-/********************************
- * If possible, convert array initializer to associative array initializer.
- */
-
-Initializer *ArrayInitializer::toAssocArrayInitializer()
-{   Expressions *keys;
-    Expressions *values;
-    Expression *e;
-
-    //printf("ArrayInitializer::toAssocArrayInitializer()\n");
-    //static int i; if (++i == 2) halt();
-    keys = new Expressions();
-    keys->setDim(value.dim);
-    values = new Expressions();
-    values->setDim(value.dim);
-
-    for (size_t i = 0; i < value.dim; i++)
-    {
-	e = (Expression *)index.data[i];
-	if (!e)
-	    goto Lno;
-	keys->data[i] = (void *)e;
-
-	Initializer *iz = (Initializer *)value.data[i];
-	if (!iz)
-	    goto Lno;
-	e = iz->toExpression();
-	if (!e)
-	    goto Lno;
-	values->data[i] = (void *)e;
-    }
-    e = new AssocArrayLiteralExp(loc, keys, values);
-    return new ExpInitializer(loc, e);
-
-Lno:
-    delete keys;
-    delete values;
-    error(loc, "not an associative array initializer");
-    return this;
-}
-
-
-Type *ArrayInitializer::inferType(Scope *sc)
-{
-    for (size_t i = 0; i < value.dim; i++)
-    {
-	if (index.data[i])
-	    goto Lno;
-    }
-    if (value.dim)
-    {
-	Initializer *iz = (Initializer *)value.data[0];
-	if (iz)
-	{   Type *t = iz->inferType(sc);
-	    t = new TypeSArray(t, new IntegerExp(value.dim));
-	    t = t->semantic(loc, sc);
-	    return t;
-	}
-    }
-
-Lno:
-    error(loc, "cannot infer type from this array initializer");
-    return Type::terror;
-}
-
-
-void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writebyte('[');
-    for (int i = 0; i < index.dim; i++)
-    {
-        if (i > 0)
-	    buf->writebyte(',');
-        Expression *ex = (Expression *)index.data[i];
-        if (ex)
-        {
-            ex->toCBuffer(buf, hgs);
-            buf->writebyte(':');
-        }
-        Initializer *iz = (Initializer *)value.data[i];
-        if (iz)
-            iz->toCBuffer(buf, hgs);
-    }
-    buf->writebyte(']');
-}
-
-
-/********************************** ExpInitializer ************************************/
-
-ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
-    : Initializer(loc)
-{
-    this->exp = exp;
-}
-
-Initializer *ExpInitializer::syntaxCopy()
-{
-    return new ExpInitializer(loc, exp->syntaxCopy());
-}
-
-Initializer *ExpInitializer::semantic(Scope *sc, Type *t)
-{
-    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
-    exp = exp->semantic(sc);
-    Type *tb = t->toBasetype();
-
-    /* Look for case of initializing a static array with a too-short
-     * string literal, such as:
-     *	char[5] foo = "abc";
-     * Allow this by doing an explicit cast, which will lengthen the string
-     * literal.
-     */
-    if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
-    {	StringExp *se = (StringExp *)exp;
-
-	if (!se->committed && se->type->ty == Tsarray &&
-	    ((TypeSArray *)se->type)->dim->toInteger() <
-	    ((TypeSArray *)t)->dim->toInteger())
-	{
-	    exp = se->castTo(sc, t);
-	    goto L1;
-	}
-    }
-
-    // Look for the case of statically initializing an array
-    // with a single member.
-    if (tb->ty == Tsarray &&
-	!tb->next->equals(exp->type->toBasetype()->next) &&
-	exp->implicitConvTo(tb->next)
-       )
-    {
-	t = tb->next;
-    }
-
-    exp = exp->implicitCastTo(sc, t);
-L1:
-    exp = exp->optimize(WANTvalue | WANTinterpret);
-    //printf("-ExpInitializer::semantic(): "); exp->print();
-    return this;
-}
-
-Type *ExpInitializer::inferType(Scope *sc)
-{
-    //printf("ExpInitializer::inferType() %s\n", toChars());
-    exp = exp->semantic(sc);
-    exp = resolveProperties(sc, exp);
-    return exp->type;
-}
-
-Expression *ExpInitializer::toExpression()
-{
-    return exp;
-}
-
-
-void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    exp->toCBuffer(buf, hgs);
-}
-
-
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "identifier.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "hdrgen.h"
+
+/********************************** Initializer *******************************/
+
+Initializer::Initializer(Loc loc)
+{
+    this->loc = loc;
+}
+
+Initializer *Initializer::syntaxCopy()
+{
+    return this;
+}
+
+Initializer *Initializer::semantic(Scope *sc, Type *t)
+{
+    return this;
+}
+
+Type *Initializer::inferType(Scope *sc)
+{
+    error(loc, "cannot infer type from initializer");
+    return Type::terror;
+}
+
+Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
+{   Initializers *a = NULL;
+
+    if (ai)
+    {
+	a = new Initializers();
+	a->setDim(ai->dim);
+	for (int i = 0; i < a->dim; i++)
+	{   Initializer *e = (Initializer *)ai->data[i];
+
+	    e = e->syntaxCopy();
+	    a->data[i] = e;
+	}
+    }
+    return a;
+}
+
+char *Initializer::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf = new OutBuffer();
+    toCBuffer(buf, &hgs);
+    return buf->toChars();
+}
+
+/********************************** VoidInitializer ***************************/
+
+VoidInitializer::VoidInitializer(Loc loc)
+    : Initializer(loc)
+{
+    type = NULL;
+}
+
+
+Initializer *VoidInitializer::syntaxCopy()
+{
+    return new VoidInitializer(loc);
+}
+
+
+Initializer *VoidInitializer::semantic(Scope *sc, Type *t)
+{
+    //printf("VoidInitializer::semantic(t = %p)\n", t);
+    type = t;
+    return this;
+}
+
+
+Expression *VoidInitializer::toExpression()
+{
+    error(loc, "void initializer has no value");
+    return new IntegerExp(0);
+}
+
+
+void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("void");
+}
+
+
+/********************************** StructInitializer *************************/
+
+StructInitializer::StructInitializer(Loc loc)
+    : Initializer(loc)
+{
+    ad = NULL;
+}
+
+Initializer *StructInitializer::syntaxCopy()
+{
+    StructInitializer *ai = new StructInitializer(loc);
+
+    assert(field.dim == value.dim);
+    ai->field.setDim(field.dim);
+    ai->value.setDim(value.dim);
+    for (int i = 0; i < field.dim; i++)
+    {    
+	ai->field.data[i] = field.data[i];
+
+	Initializer *init = (Initializer *)value.data[i];
+	init = init->syntaxCopy();
+	ai->value.data[i] = init;
+    }
+    return ai;
+}
+
+void StructInitializer::addInit(Identifier *field, Initializer *value)
+{
+    //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
+    this->field.push(field);
+    this->value.push(value);
+}
+
+Initializer *StructInitializer::semantic(Scope *sc, Type *t)
+{
+    TypeStruct *ts;
+    int errors = 0;
+
+    //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
+    vars.setDim(field.dim);
+    t = t->toBasetype();
+    if (t->ty == Tstruct)
+    {	unsigned i;
+	unsigned fieldi = 0;
+
+	ts = (TypeStruct *)t;
+	ad = ts->sym;
+	for (i = 0; i < field.dim; i++)
+	{
+	    Identifier *id = (Identifier *)field.data[i];
+	    Initializer *val = (Initializer *)value.data[i];
+	    Dsymbol *s;
+	    VarDeclaration *v;
+
+	    if (id == NULL)
+	    {
+		if (fieldi >= ad->fields.dim)
+		{   error(loc, "too many initializers for %s", ad->toChars());
+		    field.remove(i);
+		    i--;
+		    continue;
+		}
+		else
+		{
+		    s = (Dsymbol *)ad->fields.data[fieldi];
+		}
+	    }
+	    else
+	    {
+		//s = ad->symtab->lookup(id);
+		s = ad->search(loc, id, 0);
+		if (!s)
+		{
+		    error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
+		    continue;
+		}
+
+		// Find out which field index it is
+		for (fieldi = 0; 1; fieldi++)
+		{
+		    if (fieldi >= ad->fields.dim)
+		    {
+			s->error("is not a per-instance initializable field");
+			break;
+		    }
+		    if (s == (Dsymbol *)ad->fields.data[fieldi])
+			break;
+		}
+	    }
+	    if (s && (v = s->isVarDeclaration()) != NULL)
+	    {
+		val = val->semantic(sc, v->type);
+		value.data[i] = (void *)val;
+		vars.data[i] = (void *)v;
+	    }
+	    else
+	    {	error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
+		errors = 1;
+	    }
+	    fieldi++;
+	}
+    }
+    else if (t->ty == Tdelegate && value.dim == 0)
+    {	/* Rewrite as empty delegate literal { }
+	 */
+	Arguments *arguments = new Arguments;
+	Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
+	FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
+	fd->fbody = new CompoundStatement(loc, new Statements());
+	fd->endloc = loc;
+	Expression *e = new FuncExp(loc, fd);
+	ExpInitializer *ie = new ExpInitializer(loc, e);
+	return ie->semantic(sc, t);
+    }
+    else
+    {
+	error(loc, "a struct is not a valid initializer for a %s", t->toChars());
+	errors = 1;
+    }
+    if (errors)
+    {
+	field.setDim(0);
+	value.setDim(0);
+	vars.setDim(0);
+    }
+    return this;
+}
+
+
+/***************************************
+ * This works by transforming a struct initializer into
+ * a struct literal. In the future, the two should be the
+ * same thing.
+ */
+Expression *StructInitializer::toExpression()
+{   Expression *e;
+
+    //printf("StructInitializer::toExpression() %s\n", toChars());
+    if (!ad)				// if fwd referenced
+    {
+	return NULL;
+    }
+    StructDeclaration *sd = ad->isStructDeclaration();
+    if (!sd)
+	return NULL;
+    Expressions *elements = new Expressions();
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	if (field.data[i])
+	    goto Lno;
+	Initializer *iz = (Initializer *)value.data[i];
+	if (!iz)
+	    goto Lno;
+	Expression *ex = iz->toExpression();
+	if (!ex)
+	    goto Lno;
+	elements->push(ex);
+    }
+    e = new StructLiteralExp(loc, sd, elements);
+    e->type = sd->type;
+    return e;
+
+Lno:
+    delete elements;
+    //error(loc, "struct initializers as expressions are not allowed");
+    return NULL;
+}
+
+
+void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    //printf("StructInitializer::toCBuffer()\n");
+    buf->writebyte('{');
+    for (int i = 0; i < field.dim; i++)
+    {
+        if (i > 0)
+	    buf->writebyte(',');
+        Identifier *id = (Identifier *)field.data[i];
+        if (id)
+        {
+            buf->writestring(id->toChars());
+            buf->writebyte(':');
+        }
+        Initializer *iz = (Initializer *)value.data[i];
+        if (iz)
+            iz->toCBuffer(buf, hgs);
+    }
+    buf->writebyte('}');
+}
+
+/********************************** ArrayInitializer ************************************/
+
+ArrayInitializer::ArrayInitializer(Loc loc)
+    : Initializer(loc)
+{
+    dim = 0;
+    type = NULL;
+    sem = 0;
+}
+
+Initializer *ArrayInitializer::syntaxCopy()
+{
+    //printf("ArrayInitializer::syntaxCopy()\n");
+
+    ArrayInitializer *ai = new ArrayInitializer(loc);
+
+    assert(index.dim == value.dim);
+    ai->index.setDim(index.dim);
+    ai->value.setDim(value.dim);
+    for (int i = 0; i < ai->value.dim; i++)
+    {	Expression *e = (Expression *)index.data[i];
+	if (e)
+	    e = e->syntaxCopy();
+	ai->index.data[i] = e;
+
+	Initializer *init = (Initializer *)value.data[i];
+	init = init->syntaxCopy();
+	ai->value.data[i] = init;
+    }
+    return ai;
+}
+
+void ArrayInitializer::addInit(Expression *index, Initializer *value)
+{
+    this->index.push(index);
+    this->value.push(value);
+    dim = 0;
+    type = NULL;
+}
+
+Initializer *ArrayInitializer::semantic(Scope *sc, Type *t)
+{   unsigned i;
+    unsigned length;
+
+    //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
+    if (sem)				// if semantic() already run
+	return this;
+    sem = 1;
+    type = t;
+    t = t->toBasetype();
+    switch (t->ty)
+    {
+	case Tpointer:
+	case Tsarray:
+	case Tarray:
+	    break;
+
+	default:
+	    error(loc, "cannot use array to initialize %s", type->toChars());
+	    return this;
+    }
+
+    length = 0;
+    for (i = 0; i < index.dim; i++)
+    {	Expression *idx;
+	Initializer *val;
+
+	idx = (Expression *)index.data[i];
+	if (idx)
+	{   idx = idx->semantic(sc);
+	    idx = idx->optimize(WANTvalue | WANTinterpret);
+	    index.data[i] = (void *)idx;
+	    length = idx->toInteger();
+	}
+
+	val = (Initializer *)value.data[i];
+	val = val->semantic(sc, t->next);
+	value.data[i] = (void *)val;
+	length++;
+	if (length == 0)
+	    error(loc, "array dimension overflow");
+	if (length > dim)
+	    dim = length;
+    }
+    unsigned long amax = 0x80000000;
+    if ((unsigned long) dim * t->next->size() >= amax)
+	error(loc, "array dimension %u exceeds max of %llu", dim, amax / t->next->size());
+    return this;
+}
+
+/********************************
+ * If possible, convert array initializer to array literal.
+ */
+
+Expression *ArrayInitializer::toExpression()
+{   Expressions *elements;
+    Expression *e;
+
+    //printf("ArrayInitializer::toExpression()\n");
+    //static int i; if (++i == 2) halt();
+    elements = new Expressions();
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	if (index.data[i])
+	    goto Lno;
+	Initializer *iz = (Initializer *)value.data[i];
+	if (!iz)
+	    goto Lno;
+	Expression *ex = iz->toExpression();
+	if (!ex)
+	    goto Lno;
+	elements->push(ex);
+    }
+    e = new ArrayLiteralExp(loc, elements);
+    e->type = type;
+    return e;
+
+Lno:
+    delete elements;
+    error(loc, "array initializers as expressions are not allowed");
+    return NULL;
+}
+
+
+/********************************
+ * If possible, convert array initializer to associative array initializer.
+ */
+
+Initializer *ArrayInitializer::toAssocArrayInitializer()
+{   Expressions *keys;
+    Expressions *values;
+    Expression *e;
+
+    //printf("ArrayInitializer::toAssocArrayInitializer()\n");
+    //static int i; if (++i == 2) halt();
+    keys = new Expressions();
+    keys->setDim(value.dim);
+    values = new Expressions();
+    values->setDim(value.dim);
+
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	e = (Expression *)index.data[i];
+	if (!e)
+	    goto Lno;
+	keys->data[i] = (void *)e;
+
+	Initializer *iz = (Initializer *)value.data[i];
+	if (!iz)
+	    goto Lno;
+	e = iz->toExpression();
+	if (!e)
+	    goto Lno;
+	values->data[i] = (void *)e;
+    }
+    e = new AssocArrayLiteralExp(loc, keys, values);
+    return new ExpInitializer(loc, e);
+
+Lno:
+    delete keys;
+    delete values;
+    error(loc, "not an associative array initializer");
+    return this;
+}
+
+
+Type *ArrayInitializer::inferType(Scope *sc)
+{
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	if (index.data[i])
+	    goto Lno;
+    }
+    if (value.dim)
+    {
+	Initializer *iz = (Initializer *)value.data[0];
+	if (iz)
+	{   Type *t = iz->inferType(sc);
+	    t = new TypeSArray(t, new IntegerExp(value.dim));
+	    t = t->semantic(loc, sc);
+	    return t;
+	}
+    }
+
+Lno:
+    error(loc, "cannot infer type from this array initializer");
+    return Type::terror;
+}
+
+
+void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writebyte('[');
+    for (int i = 0; i < index.dim; i++)
+    {
+        if (i > 0)
+	    buf->writebyte(',');
+        Expression *ex = (Expression *)index.data[i];
+        if (ex)
+        {
+            ex->toCBuffer(buf, hgs);
+            buf->writebyte(':');
+        }
+        Initializer *iz = (Initializer *)value.data[i];
+        if (iz)
+            iz->toCBuffer(buf, hgs);
+    }
+    buf->writebyte(']');
+}
+
+
+/********************************** ExpInitializer ************************************/
+
+ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
+    : Initializer(loc)
+{
+    this->exp = exp;
+}
+
+Initializer *ExpInitializer::syntaxCopy()
+{
+    return new ExpInitializer(loc, exp->syntaxCopy());
+}
+
+Initializer *ExpInitializer::semantic(Scope *sc, Type *t)
+{
+    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
+    exp = exp->semantic(sc);
+    Type *tb = t->toBasetype();
+
+    /* Look for case of initializing a static array with a too-short
+     * string literal, such as:
+     *	char[5] foo = "abc";
+     * Allow this by doing an explicit cast, which will lengthen the string
+     * literal.
+     */
+    if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
+    {	StringExp *se = (StringExp *)exp;
+
+	if (!se->committed && se->type->ty == Tsarray &&
+	    ((TypeSArray *)se->type)->dim->toInteger() <
+	    ((TypeSArray *)t)->dim->toInteger())
+	{
+	    exp = se->castTo(sc, t);
+	    goto L1;
+	}
+    }
+
+    // Look for the case of statically initializing an array
+    // with a single member.
+    if (tb->ty == Tsarray &&
+	!tb->next->equals(exp->type->toBasetype()->next) &&
+	exp->implicitConvTo(tb->next)
+       )
+    {
+	t = tb->next;
+    }
+
+    exp = exp->implicitCastTo(sc, t);
+L1:
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    //printf("-ExpInitializer::semantic(): "); exp->print();
+    return this;
+}
+
+Type *ExpInitializer::inferType(Scope *sc)
+{
+    //printf("ExpInitializer::inferType() %s\n", toChars());
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    return exp->type;
+}
+
+Expression *ExpInitializer::toExpression()
+{
+    return exp;
+}
+
+
+void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    exp->toCBuffer(buf, hgs);
+}
+
+
+
--- a/dmd/inline.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/inline.c	Sat Jul 12 19:38:31 2008 +0200
@@ -860,7 +860,7 @@
 }
 
 
-#if V2
+#if DMDV2
 Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss)
 {
     lwr = lwr->inlineScan(iss);
@@ -1290,7 +1290,7 @@
 #endif
 	isSynchronized() ||
 	isImportedSymbol() ||
-#if V2
+#if DMDV2
 	closureVars.dim ||	// no nested references to this frame
 #else
 	nestedFrameRef ||	// no nested references to this frame
--- a/dmd/interpret.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/interpret.c	Sat Jul 12 19:38:31 2008 +0200
@@ -729,7 +729,7 @@
     return e;
 }
 
-#if V2
+#if DMDV2
 Expression *ForeachRangeStatement::interpret(InterState *istate)
 {
 #if LOG
@@ -989,7 +989,7 @@
     SymbolDeclaration *s = d->isSymbolDeclaration();
     if (v)
     {
-#if V2
+#if DMDV2
 	if ((v->isConst() || v->isInvariant()) && v->init && !v->value)
 #else
 	if (v->isConst() && v->init)
@@ -1045,7 +1045,7 @@
 	    else if (v->init->isVoidInitializer())
 		e = NULL;
 	}
-#if V2
+#if DMDV2
 	else if (s == v && (v->isConst() || v->isInvariant()) && v->init)
 #else
 	else if (s == v && v->isConst() && v->init)
@@ -1855,7 +1855,7 @@
 	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
 	if (fd)
 	{
-#if V2
+#if DMDV2
 	    enum BUILTIN b = fd->isBuiltin();
 	    if (b)
 	    {	Expressions args;
--- a/dmd/lexer.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/lexer.c	Sat Jul 12 19:38:31 2008 +0200
@@ -568,7 +568,7 @@
 		t->value = hexStringConstant(t);
 		return;
 
-#if V2
+#if DMDV2
 	    case 'q':
 		if (p[1] == '"')
 		{
@@ -627,7 +627,7 @@
 	    case 'a':  	case 'b':   case 'c':   case 'd':   case 'e':
 	    case 'f':  	case 'g':   case 'h':   case 'i':   case 'j':
 	    case 'k':  	            case 'm':   case 'n':   case 'o':
-#if V2
+#if DMDV2
 	    case 'p':  	/*case 'q': case 'r':*/ case 's':   case 't':
 #else
 	    case 'p':  	case 'q': /*case 'r':*/ case 's':   case 't':
@@ -677,6 +677,7 @@
 			sprintf(timestamp, "%.24s", p);
 		    }
 
+#if DMDV1
 		    if (mod && id == Id::FILE)
 		    {
 			t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars());
@@ -687,7 +688,9 @@
 			t->value = TOKint64v;
 			t->uns64value = loc.linnum;
 		    }
-		    else if (id == Id::DATE)
+		    else
+#endif
+		    if (id == Id::DATE)
 		    {
 			t->ustring = (unsigned char *)date;
 			goto Lstring;
@@ -730,7 +733,7 @@
 			t->value = TOKint64v;
 			t->uns64value = major * 1000 + minor;
 		    }
-#if V2
+#if DMDV2
 		    else if (id == Id::EOFX)
 		    {
 			t->value = TOKeof;
@@ -1476,7 +1479,7 @@
 }
 
 
-#if V2
+#if DMDV2
 /**************************************
  * Lex delimited strings:
  *	q"(foo(xxx))"   // "foo(xxx)"
@@ -2917,11 +2920,14 @@
     // Added after 1.0
     {	"ref",		TOKref		},
     {	"macro",	TOKmacro	},
-#if V2
+#if DMDV2
     {	"pure",		TOKpure		},
     {	"nothrow",	TOKnothrow	},
+    {	"__thread",	TOKtls		},
     {	"__traits",	TOKtraits	},
     {	"__overloadset", TOKoverloadset	},
+    {	"__FILE__",	TOKfile		},
+    {	"__LINE__",	TOKline		},
 #endif
 };
 
@@ -2974,7 +2980,7 @@
     Token::tochars[TOKxorass]		= "^=";
     Token::tochars[TOKassign]		= "=";
     Token::tochars[TOKconstruct]	= "=";
-#if V2
+#if DMDV2
     Token::tochars[TOKblit]		= "=";
 #endif
     Token::tochars[TOKlt]		= "<";
--- a/dmd/lexer.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/lexer.h	Sat Jul 12 19:38:31 2008 +0200
@@ -150,10 +150,14 @@
 	// Added after 1.0
 	TOKref,
 	TOKmacro,
-#if V2
+#if DMDV2
 	TOKtraits,
 	TOKoverloadset,
 	TOKpure,
+	TOKnothrow,
+	TOKtls,
+	TOKline,
+	TOKfile,
 #endif
 
 	TOKMAX
@@ -273,7 +277,7 @@
     unsigned escapeSequence();
     TOK wysiwygStringConstant(Token *t, int tc);
     TOK hexStringConstant(Token *t);
-#if V2
+#if DMDV2
     TOK delimitedStringConstant(Token *t);
     TOK tokenStringConstant(Token *t);
 #endif
--- a/dmd/mars.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/mars.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1043,7 +1043,7 @@
 	if (global.params.verbose)
 	    printf("code      %s\n", m->toChars());
 	if (global.params.obj)
-	    m->genobjfile();
+	    m->genobjfile(0);
 	if (global.errors)
 	    m->deleteObjFile();
 	else
--- a/dmd/mars.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/mars.h	Sat Jul 12 19:38:31 2008 +0200
@@ -32,7 +32,7 @@
 /* Changes for the GDC compiler by David Friedman */
 #endif
 
-#define V2	0	// Version 2.0 features
+#define DMDV2	0	// Version 2.0 features
 #define BREAKABI 1	// 0 if not ready to break the ABI just yet
 
 struct Array;
@@ -300,7 +300,7 @@
 {
     MATCHnomatch,	// no match
     MATCHconvert,	// match with conversions
-#if V2
+#if DMDV2
     MATCHconst,		// match with conversion to const
 #endif
     MATCHexact		// exact match
--- a/dmd/module.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/module.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,983 +1,982 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#if _MSC_VER || __MINGW32__
-#include <malloc.h>
-#endif
-
-#if IN_GCC
-#include "gdc_alloca.h"
-#endif
-
-#include "mem.h"
-
-#include "mars.h"
-#include "module.h"
-#include "parse.h"
-#include "scope.h"
-#include "identifier.h"
-#include "id.h"
-#include "import.h"
-#include "dsymbol.h"
-#include "hdrgen.h"
-#include "lexer.h"
-
-#define MARS 1
-#include "html.h"
-
-#ifdef IN_GCC
-#include "d-dmd-gcc.h"
-#endif
-
-ClassDeclaration *Module::moduleinfo;
-
-Module *Module::rootModule;
-DsymbolTable *Module::modules;
-Array Module::amodules;
-
-Array Module::deferred;	// deferred Dsymbol's needing semantic() run on them
-unsigned Module::dprogress;
-
-void Module::init()
-{
-    modules = new DsymbolTable();
-}
-
-Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen)
-	: Package(ident)
-{
-    FileName *srcfilename;
-    FileName *cfilename;
-    FileName *hfilename;
-    FileName *objfilename;
-    FileName *llfilename;
-    FileName *bcfilename;
-    FileName *symfilename;
-
-//    printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
-    this->arg = filename;
-    md = NULL;
-    errors = 0;
-    numlines = 0;
-    members = NULL;
-    isHtml = 0;
-    isDocFile = 0;
-    needmoduleinfo = 0;
-#ifdef IN_GCC
-    strictlyneedmoduleinfo = 0;
-#endif
-    insearch = 0;
-    searchCacheIdent = NULL;
-    searchCacheSymbol = NULL;
-    searchCacheFlags = 0;
-    semanticstarted = 0;
-    semanticdone = 0;
-    decldefs = NULL;
-    vmoduleinfo = NULL;
-    massert = NULL;
-    marray = NULL;
-    sictor = NULL;
-    sctor = NULL;
-    sdtor = NULL;
-    stest = NULL;
-    sfilename = NULL;
-    root = 0;
-    importedFrom = NULL;
-    srcfile = NULL;
-    docfile = NULL;
-
-    debuglevel = 0;
-    debugids = NULL;
-    debugidsNot = NULL;
-    versionlevel = 0;
-    versionids = NULL;
-    versionidsNot = NULL;
-
-    macrotable = NULL;
-    escapetable = NULL;
-    cov = NULL;
-    covb = NULL;
-
-    srcfilename = FileName::defaultExt(filename, global.mars_ext);
-    if (!srcfilename->equalsExt(global.mars_ext))
-    {
-	if (srcfilename->equalsExt("html") ||
-	    srcfilename->equalsExt("htm")  ||
-	    srcfilename->equalsExt("xhtml"))
-	    isHtml = 1;
-	else
-	{   error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext);
-	    fatal();
-	}
-    }
-
-    char *argobj;
-    if (global.params.objname)
-	argobj = global.params.objname;
-    else if (global.params.preservePaths)
-	argobj = filename;
-    else
-	argobj = FileName::name(filename);
-    if (!FileName::absolute(argobj))
-    {
-	argobj = FileName::combine(global.params.objdir, argobj);
-    }
-
-    if (global.params.objname)
-	objfilename = new FileName(argobj, 0);
-    else
-    objfilename = FileName::forceExt(argobj, global.obj_ext);
-
-    llfilename = FileName::forceExt(argobj, global.ll_ext);
-    bcfilename = FileName::forceExt(argobj, global.bc_ext);
-
-    symfilename = FileName::forceExt(filename, global.sym_ext);
-
-    srcfile = new File(srcfilename);
-
-    if (doDocComment)
-    {
-	setDocfile();
-    }
-
-    if (doHdrGen)
-    {
-	setHdrfile();
-    }
-
-    objfile = new File(objfilename);
-    bcfile = new File(bcfilename);
-    llfile = new File(llfilename);
-    symfile = new File(symfilename);
-}
-
-void Module::setDocfile()
-{
-    FileName *docfilename;
-    char *argdoc;
-
-    if (global.params.docname)
-	argdoc = global.params.docname;
-    else if (global.params.preservePaths)
-	argdoc = (char *)arg;
-    else
-	argdoc = FileName::name((char *)arg);
-    if (!FileName::absolute(argdoc))
-    {	//FileName::ensurePathExists(global.params.docdir);
-	argdoc = FileName::combine(global.params.docdir, argdoc);
-    }
-    if (global.params.docname)
-	docfilename = new FileName(argdoc, 0);
-    else
-	docfilename = FileName::forceExt(argdoc, global.doc_ext);
-
-    if (docfilename->equals(srcfile->name))
-    {   error("Source file and documentation file have same name '%s'", srcfile->name->str);
-	fatal();
-    }
-
-    docfile = new File(docfilename);
-}
-
-void Module::setHdrfile()
-{
-    FileName *hdrfilename;
-    char *arghdr;
-
-    if (global.params.hdrname)
-	arghdr = global.params.hdrname;
-    else if (global.params.preservePaths)
-	arghdr = (char *)arg;
-    else
-	arghdr = FileName::name((char *)arg);
-    if (!FileName::absolute(arghdr))
-    {	//FileName::ensurePathExists(global.params.hdrdir);
-	arghdr = FileName::combine(global.params.hdrdir, arghdr);
-    }
-    if (global.params.hdrname)
-	hdrfilename = new FileName(arghdr, 0);
-    else
-	hdrfilename = FileName::forceExt(arghdr, global.hdr_ext);
-
-    if (hdrfilename->equals(srcfile->name))
-    {   error("Source file and 'header' file have same name '%s'", srcfile->name->str);
-	fatal();
-    }
-
-    hdrfile = new File(hdrfilename);
-}
-
-void Module::deleteObjFile()
-{
-    if (global.params.obj)
-	objfile->remove();
-    //if (global.params.llvmBC)
-    bcfile->remove();
-    if (docfile)
-	docfile->remove();
-}
-
-Module::~Module()
-{
-}
-
-char *Module::kind()
-{
-    return "module";
-}
-
-Module *Module::load(Loc loc, Array *packages, Identifier *ident)
-{   Module *m;
-    char *filename;
-
-    //printf("Module::load(ident = '%s')\n", ident->toChars());
-
-    // Build module filename by turning:
-    //	foo.bar.baz
-    // into:
-    //	foo\bar\baz
-    filename = ident->toChars();
-    if (packages && packages->dim)
-    {
-	OutBuffer buf;
-	int i;
-
-	for (i = 0; i < packages->dim; i++)
-	{   Identifier *pid = (Identifier *)packages->data[i];
-
-	    buf.writestring(pid->toChars());
-#if _WIN32
-	    buf.writeByte('\\');
-#else
-	    buf.writeByte('/');
-#endif
-	}
-	buf.writestring(filename);
-	buf.writeByte(0);
-	filename = (char *)buf.extractData();
-    }
-
-    m = new Module(filename, ident, 0, 0);
-    m->loc = loc;
-
-    /* Search along global.path for .di file, then .d file.
-     */
-    char *result = NULL;
-    FileName *fdi = FileName::forceExt(filename, global.hdr_ext);
-    FileName *fd  = FileName::forceExt(filename, global.mars_ext);
-    char *sdi = fdi->toChars();
-    char *sd  = fd->toChars();
-
-    if (FileName::exists(sdi))
-	result = sdi;
-    else if (FileName::exists(sd))
-	result = sd;
-    else if (FileName::absolute(filename))
-	;
-    else if (!global.path)
-	;
-    else
-    {
-	for (size_t i = 0; i < global.path->dim; i++)
-	{
-	    char *p = (char *)global.path->data[i];
-	    char *n = FileName::combine(p, sdi);
-	    if (FileName::exists(n))
-	    {	result = n;
-		break;
-	    }
-	    mem.free(n);
-	    n = FileName::combine(p, sd);
-	    if (FileName::exists(n))
-	    {	result = n;
-		break;
-	    }
-	    mem.free(n);
-	}
-    }
-    if (result)
-	m->srcfile = new File(result);
-
-    if (global.params.verbose)
-    {
-	printf("import    ");
-	if (packages)
-	{
-	    for (size_t i = 0; i < packages->dim; i++)
-	    {   Identifier *pid = (Identifier *)packages->data[i];
-		printf("%s.", pid->toChars());
-	    }
-	}
-	printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars());
-    }
-
-    m->read(loc);
-    m->parse();
-
-#ifdef IN_GCC
-    d_gcc_magic_module(m);
-#endif
-
-    return m;
-}
-
-void Module::read(Loc loc)
-{
-    //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
-    if (srcfile->read())
-    {	error(loc, "cannot read file '%s'", srcfile->toChars());
-	fatal();
-    }
-}
-
-inline unsigned readwordLE(unsigned short *p)
-{
-#if __I86__
-    return *p;
-#else
-    return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0];
-#endif
-}
-
-inline unsigned readwordBE(unsigned short *p)
-{
-    return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1];
-}
-
-inline unsigned readlongLE(unsigned *p)
-{
-#if __I86__
-    return *p;
-#else
-    return ((unsigned char *)p)[0] |
-	(((unsigned char *)p)[1] << 8) |
-	(((unsigned char *)p)[2] << 16) |
-	(((unsigned char *)p)[3] << 24);
-#endif
-}
-
-inline unsigned readlongBE(unsigned *p)
-{
-    return ((unsigned char *)p)[3] |
-	(((unsigned char *)p)[2] << 8) |
-	(((unsigned char *)p)[1] << 16) |
-	(((unsigned char *)p)[0] << 24);
-}
-
-#if IN_GCC
-void Module::parse(bool dump_source)
-#else
-void Module::parse()
-#endif
-{   char *srcname;
-    unsigned char *buf;
-    unsigned buflen;
-    unsigned le;
-    unsigned bom;
-
-    //printf("Module::parse()\n");
-
-    srcname = srcfile->name->toChars();
-    //printf("Module::parse(srcname = '%s')\n", srcname);
-
-    buf = srcfile->buffer;
-    buflen = srcfile->len;
-
-    if (buflen >= 2)
-    {
-	/* Convert all non-UTF-8 formats to UTF-8.
-	 * BOM : http://www.unicode.org/faq/utf_bom.html
-	 * 00 00 FE FF	UTF-32BE, big-endian
-	 * FF FE 00 00	UTF-32LE, little-endian
-	 * FE FF	UTF-16BE, big-endian
-	 * FF FE	UTF-16LE, little-endian
-	 * EF BB BF	UTF-8
-	 */
-
-	bom = 1;		// assume there's a BOM
-	if (buf[0] == 0xFF && buf[1] == 0xFE)
-	{
-	    if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
-	    {	// UTF-32LE
-		le = 1;
-
-	    Lutf32:
-		OutBuffer dbuf;
-		unsigned *pu = (unsigned *)(buf);
-		unsigned *pumax = &pu[buflen / 4];
-
-		if (buflen & 3)
-		{   error("odd length of UTF-32 char source %u", buflen);
-		    fatal();
-		}
-
-		dbuf.reserve(buflen / 4);
-		for (pu += bom; pu < pumax; pu++)
-		{   unsigned u;
-
-		    u = le ? readlongLE(pu) : readlongBE(pu);
-		    if (u & ~0x7F)
-		    {
-			if (u > 0x10FFFF)
-			{   error("UTF-32 value %08x greater than 0x10FFFF", u);
-			    fatal();
-			}
-			dbuf.writeUTF8(u);
-		    }
-		    else
-			dbuf.writeByte(u);
-		}
-		dbuf.writeByte(0);		// add 0 as sentinel for scanner
-		buflen = dbuf.offset - 1;	// don't include sentinel in count
-		buf = (unsigned char *) dbuf.extractData();
-	    }
-	    else
-	    {   // UTF-16LE (X86)
-		// Convert it to UTF-8
-		le = 1;
-
-	    Lutf16:
-		OutBuffer dbuf;
-		unsigned short *pu = (unsigned short *)(buf);
-		unsigned short *pumax = &pu[buflen / 2];
-
-		if (buflen & 1)
-		{   error("odd length of UTF-16 char source %u", buflen);
-		    fatal();
-		}
-
-		dbuf.reserve(buflen / 2);
-		for (pu += bom; pu < pumax; pu++)
-		{   unsigned u;
-
-		    u = le ? readwordLE(pu) : readwordBE(pu);
-		    if (u & ~0x7F)
-		    {	if (u >= 0xD800 && u <= 0xDBFF)
-			{   unsigned u2;
-
-			    if (++pu > pumax)
-			    {   error("surrogate UTF-16 high value %04x at EOF", u);
-				fatal();
-			    }
-			    u2 = le ? readwordLE(pu) : readwordBE(pu);
-			    if (u2 < 0xDC00 || u2 > 0xDFFF)
-			    {   error("surrogate UTF-16 low value %04x out of range", u2);
-				fatal();
-			    }
-			    u = (u - 0xD7C0) << 10;
-			    u |= (u2 - 0xDC00);
-			}
-			else if (u >= 0xDC00 && u <= 0xDFFF)
-			{   error("unpaired surrogate UTF-16 value %04x", u);
-			    fatal();
-			}
-			else if (u == 0xFFFE || u == 0xFFFF)
-			{   error("illegal UTF-16 value %04x", u);
-			    fatal();
-			}
-			dbuf.writeUTF8(u);
-		    }
-		    else
-			dbuf.writeByte(u);
-		}
-		dbuf.writeByte(0);		// add 0 as sentinel for scanner
-		buflen = dbuf.offset - 1;	// don't include sentinel in count
-		buf = (unsigned char *) dbuf.extractData();
-	    }
-	}
-	else if (buf[0] == 0xFE && buf[1] == 0xFF)
-	{   // UTF-16BE
-	    le = 0;
-	    goto Lutf16;
-	}
-	else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
-	{   // UTF-32BE
-	    le = 0;
-	    goto Lutf32;
-	}
-	else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
-	{   // UTF-8
-
-	    buf += 3;
-	    buflen -= 3;
-	}
-	else
-	{
-	    /* There is no BOM. Make use of Arcane Jill's insight that
-	     * the first char of D source must be ASCII to
-	     * figure out the encoding.
-	     */
-
-	    bom = 0;
-	    if (buflen >= 4)
-	    {   if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
-		{   // UTF-32LE
-		    le = 1;
-		    goto Lutf32;
-		}
-		else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
-		{   // UTF-32BE
-		    le = 0;
-		    goto Lutf32;
-		}
-	    }
-	    if (buflen >= 2)
-	    {
-		if (buf[1] == 0)
-		{   // UTF-16LE
-		    le = 1;
-		    goto Lutf16;
-		}
-		else if (buf[0] == 0)
-		{   // UTF-16BE
-		    le = 0;
-		    goto Lutf16;
-		}
-	    }
-
-	    // It's UTF-8
-	    if (buf[0] >= 0x80)
-	    {	error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
-		fatal();
-	    }
-	}
-    }
-
-#ifdef IN_GCC
-    // dump utf-8 encoded source
-    if (dump_source)
-    {	// %% srcname could contain a path ...
-	d_gcc_dump_source(srcname, "utf-8", buf, buflen);
-    }
-#endif
-
-    /* If it starts with the string "Ddoc", then it's a documentation
-     * source file.
-     */
-    if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
-    {
-	comment = buf + 4;
-	isDocFile = 1;
-	if (!docfile)
-	    setDocfile();
-	return;
-    }
-    if (isHtml)
-    {
-	OutBuffer *dbuf = new OutBuffer();
-	Html h(srcname, buf, buflen);
-	h.extractCode(dbuf);
-	buf = dbuf->data;
-	buflen = dbuf->offset;
-#ifdef IN_GCC
-	// dump extracted source
-	if (dump_source)
-	    d_gcc_dump_source(srcname, "d.utf-8", buf, buflen);
-#endif
-    }
-    Parser p(this, buf, buflen, docfile != NULL);
-    p.nextToken();
-    members = p.parseModule();
-    md = p.md;
-    numlines = p.loc.linnum;
-
-    DsymbolTable *dst;
-
-    if (md)
-    {	this->ident = md->id;
-	dst = Package::resolve(md->packages, &this->parent, NULL);
-    }
-    else
-    {
-	dst = modules;
-
-	/* Check to see if module name is a valid identifier
-	 */
-	if (!Lexer::isValidIdentifier(this->ident->toChars()))
-	    error("has non-identifier characters in filename, use module declaration instead");
-    }
-
-    // Update global list of modules
-    if (!dst->insert(this))
-    {
-	if (md)
-	    error(loc, "is in multiple packages %s", md->toChars());
-	else
-	    error(loc, "is in multiple defined");
-    }
-    else
-    {
-	amodules.push(this);
-    }
-}
-
-void Module::semantic()
-{   int i;
-
-    if (semanticstarted)
-	return;
-
-    //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
-    semanticstarted = 1;
-
-    // Note that modules get their own scope, from scratch.
-    // This is so regardless of where in the syntax a module
-    // gets imported, it is unaffected by context.
-    Scope *sc = Scope::createGlobal(this);	// create root scope
-
-    //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
-
-    // Add import of "object" if this module isn't "object"
-    if (ident != Id::object)
-    {
-	Import *im = new Import(0, NULL, Id::object, NULL, 0);
-	members->shift(im);
-    }
-
-    // Add all symbols into module's symbol table
-    symtab = new DsymbolTable();
-    for (i = 0; i < members->dim; i++)
-    {	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	s->addMember(NULL, sc->scopesym, 1);
-    }
-
-    // Pass 1 semantic routines: do public side of the definition
-    for (i = 0; i < members->dim; i++)
-    {	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	//printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
-	s->semantic(sc);
-	runDeferredSemantic();
-    }
-
-    sc = sc->pop();
-    sc->pop();
-    semanticdone = semanticstarted;
-    //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
-}
-
-void Module::semantic2()
-{   int i;
-
-    if (deferred.dim)
-    {
-	for (int i = 0; i < deferred.dim; i++)
-	{
-	    Dsymbol *sd = (Dsymbol *)deferred.data[i];
-
-	    sd->error("unable to resolve forward reference in definition");
-	}
-	return;
-    }
-    //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
-    if (semanticstarted >= 2)
-	return;
-    assert(semanticstarted == 1);
-    semanticstarted = 2;
-
-    // Note that modules get their own scope, from scratch.
-    // This is so regardless of where in the syntax a module
-    // gets imported, it is unaffected by context.
-    Scope *sc = Scope::createGlobal(this);	// create root scope
-    //printf("Module = %p\n", sc.scopesym);
-
-    // Pass 2 semantic routines: do initializers and function bodies
-    for (i = 0; i < members->dim; i++)
-    {	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	s->semantic2(sc);
-    }
-
-    sc = sc->pop();
-    sc->pop();
-    semanticdone = semanticstarted;
-    //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
-}
-
-void Module::semantic3()
-{   int i;
-
-    //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
-    if (semanticstarted >= 3)
-	return;
-    assert(semanticstarted == 2);
-    semanticstarted = 3;
-
-    // Note that modules get their own scope, from scratch.
-    // This is so regardless of where in the syntax a module
-    // gets imported, it is unaffected by context.
-    Scope *sc = Scope::createGlobal(this);	// create root scope
-    //printf("Module = %p\n", sc.scopesym);
-
-    // Pass 3 semantic routines: do initializers and function bodies
-    for (i = 0; i < members->dim; i++)
-    {	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	//printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
-	s->semantic3(sc);
-    }
-
-    sc = sc->pop();
-    sc->pop();
-    semanticdone = semanticstarted;
-}
-
-void Module::inlineScan()
-{   int i;
-
-    if (semanticstarted >= 4)
-	return;
-    assert(semanticstarted == 3);
-    semanticstarted = 4;
-
-    // Note that modules get their own scope, from scratch.
-    // This is so regardless of where in the syntax a module
-    // gets imported, it is unaffected by context.
-    //printf("Module = %p\n", sc.scopesym);
-
-    for (i = 0; i < members->dim; i++)
-    {	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	//if (global.params.verbose)
-	    //printf("inline scan symbol %s\n", s->toChars());
-
-	s->inlineScan();
-    }
-    semanticdone = semanticstarted;
-}
-
-/****************************************************
- */
-
-void Module::gensymfile()
-{
-    OutBuffer buf;
-    HdrGenState hgs;
-    int i;
-
-    //printf("Module::gensymfile()\n");
-
-    buf.printf("// Sym file generated from '%s'", srcfile->toChars());
-    buf.writenl();
-
-    for (i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	s->toCBuffer(&buf, &hgs);
-    }
-
-    // Transfer image to file
-    symfile->setbuffer(buf.data, buf.offset);
-    buf.data = NULL;
-
-    symfile->writev();
-}
-
-/**********************************
- * Determine if we need to generate an instance of ModuleInfo
- * for this Module.
- */
-
-int Module::needModuleInfo()
-{
-    return needmoduleinfo || global.params.cov;
-}
-
-Dsymbol *Module::search(Loc loc, Identifier *ident, int flags)
-{
-    /* Since modules can be circularly referenced,
-     * need to stop infinite recursive searches.
-     */
-
-    //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
-    Dsymbol *s;
-    if (insearch)
-	s = NULL;
-    else if (searchCacheIdent == ident && searchCacheFlags == flags)
-	s = searchCacheSymbol;
-    else
-    {
-	insearch = 1;
-	s = ScopeDsymbol::search(loc, ident, flags);
-	insearch = 0;
-
-	searchCacheIdent = ident;
-	searchCacheSymbol = s;
-	searchCacheFlags = flags;
-    }
-    return s;
-}
-
-/*******************************************
- * Can't run semantic on s now, try again later.
- */
-
-void Module::addDeferredSemantic(Dsymbol *s)
-{
-    // Don't add it if it is already there
-    for (int i = 0; i < deferred.dim; i++)
-    {
-	Dsymbol *sd = (Dsymbol *)deferred.data[i];
-
-	if (sd == s)
-	    return;
-    }
-
-    //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
-    deferred.push(s);
-}
-
-
-/******************************************
- * Run semantic() on deferred symbols.
- */
-
-void Module::runDeferredSemantic()
-{
-    size_t len;
-
-    static int nested;
-    if (nested)
-	return;
-    //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
-    nested++;
-
-    do
-    {
-	dprogress = 0;
-	len = deferred.dim;
-	if (!len)
-	    break;
-
-	Dsymbol **todo;
-	Dsymbol *tmp;
-	if (len == 1)
-	{
-	    todo = &tmp;
-	}
-	else
-	{
-	    todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *));
-	    assert(todo);
-	}
-	memcpy(todo, deferred.data, len * sizeof(Dsymbol *));
-	deferred.setDim(0);
-
-	for (int i = 0; i < len; i++)
-	{
-	    Dsymbol *s = todo[i];
-
-	    s->semantic(NULL);
-	    //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
-	}
-	//printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
-    } while (deferred.dim < len || dprogress);	// while making progress
-    nested--;
-    //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
-}
-
-/* =========================== ModuleDeclaration ===================== */
-
-ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id)
-{
-    this->packages = packages;
-    this->id = id;
-}
-
-char *ModuleDeclaration::toChars()
-{
-    OutBuffer buf;
-    int i;
-
-    if (packages && packages->dim)
-    {
-	for (i = 0; i < packages->dim; i++)
-	{   Identifier *pid = (Identifier *)packages->data[i];
-
-	    buf.writestring(pid->toChars());
-	    buf.writeByte('.');
-	}
-    }
-    buf.writestring(id->toChars());
-    buf.writeByte(0);
-    return (char *)buf.extractData();
-}
-
-/* =========================== Package ===================== */
-
-Package::Package(Identifier *ident)
-	: ScopeDsymbol(ident)
-{
-}
-
-
-char *Package::kind()
-{
-    return "package";
-}
-
-
-DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg)
-{
-    DsymbolTable *dst = Module::modules;
-    Dsymbol *parent = NULL;
-
-    //printf("Package::resolve()\n");
-    if (ppkg)
-	*ppkg = NULL;
-
-    if (packages)
-    {   int i;
-
-	for (i = 0; i < packages->dim; i++)
-	{   Identifier *pid = (Identifier *)packages->data[i];
-	    Dsymbol *p;
-
-	    p = dst->lookup(pid);
-	    if (!p)
-	    {
-		p = new Package(pid);
-		dst->insert(p);
-		p->parent = parent;
-		((ScopeDsymbol *)p)->symtab = new DsymbolTable();
-	    }
-	    else
-	    {
-		assert(p->isPackage());
-		if (p->isModule())
-		{   p->error("module and package have the same name");
-		    fatal();
-		    break;
-		}
-	    }
-	    parent = p;
-	    dst = ((Package *)p)->symtab;
-	    if (ppkg && !*ppkg)
-		*ppkg = (Package *)p;
-	}
-	if (pparent)
-	{
-	    *pparent = parent;
-	}
-    }
-    return dst;
-}
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _MSC_VER || __MINGW32__
+#include <malloc.h>
+#endif
+
+#if IN_GCC
+#include "gdc_alloca.h"
+#endif
+
+#include "mem.h"
+
+#include "mars.h"
+#include "module.h"
+#include "parse.h"
+#include "scope.h"
+#include "identifier.h"
+#include "id.h"
+#include "import.h"
+#include "dsymbol.h"
+#include "hdrgen.h"
+#include "lexer.h"
+
+#define MARS 1
+#include "html.h"
+
+#ifdef IN_GCC
+#include "d-dmd-gcc.h"
+#endif
+
+ClassDeclaration *Module::moduleinfo;
+
+Module *Module::rootModule;
+DsymbolTable *Module::modules;
+Array Module::amodules;
+
+Array Module::deferred;	// deferred Dsymbol's needing semantic() run on them
+unsigned Module::dprogress;
+
+void Module::init()
+{
+    modules = new DsymbolTable();
+}
+
+Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+	: Package(ident)
+{
+    FileName *srcfilename;
+    FileName *cfilename;
+    FileName *hfilename;
+    FileName *objfilename;
+    FileName *llfilename;
+    FileName *bcfilename;
+    FileName *symfilename;
+
+//    printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
+    this->arg = filename;
+    md = NULL;
+    errors = 0;
+    numlines = 0;
+    members = NULL;
+    isHtml = 0;
+    isDocFile = 0;
+    needmoduleinfo = 0;
+#ifdef IN_GCC
+    strictlyneedmoduleinfo = 0;
+#endif
+    insearch = 0;
+    searchCacheIdent = NULL;
+    searchCacheSymbol = NULL;
+    searchCacheFlags = 0;
+    semanticstarted = 0;
+    semanticdone = 0;
+    decldefs = NULL;
+    vmoduleinfo = NULL;
+    massert = NULL;
+    marray = NULL;
+    sictor = NULL;
+    sctor = NULL;
+    sdtor = NULL;
+    stest = NULL;
+    sfilename = NULL;
+    root = 0;
+    importedFrom = NULL;
+    srcfile = NULL;
+    docfile = NULL;
+
+    debuglevel = 0;
+    debugids = NULL;
+    debugidsNot = NULL;
+    versionlevel = 0;
+    versionids = NULL;
+    versionidsNot = NULL;
+
+    macrotable = NULL;
+    escapetable = NULL;
+    doppelganger = 0;
+    cov = NULL;
+    covb = NULL;
+
+    srcfilename = FileName::defaultExt(filename, global.mars_ext);
+    if (!srcfilename->equalsExt(global.mars_ext) &&
+        !srcfilename->equalsExt("dd"))
+    {
+	if (srcfilename->equalsExt("html") ||
+	    srcfilename->equalsExt("htm")  ||
+	    srcfilename->equalsExt("xhtml"))
+	    isHtml = 1;
+	else
+	{   error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext);
+	    fatal();
+	}
+    }
+
+    char *argobj;
+    if (global.params.objname)
+	argobj = global.params.objname;
+    else if (global.params.preservePaths)
+	argobj = filename;
+    else
+	argobj = FileName::name(filename);
+    if (!FileName::absolute(argobj))
+    {
+	argobj = FileName::combine(global.params.objdir, argobj);
+    }
+
+    if (global.params.objname)
+	objfilename = new FileName(argobj, 0);
+    else
+    objfilename = FileName::forceExt(argobj, global.obj_ext);
+
+    llfilename = FileName::forceExt(argobj, global.ll_ext);
+    bcfilename = FileName::forceExt(argobj, global.bc_ext);
+
+    symfilename = FileName::forceExt(filename, global.sym_ext);
+
+    srcfile = new File(srcfilename);
+
+    if (doDocComment)
+    {
+	setDocfile();
+    }
+
+    if (doHdrGen)
+    {
+	setHdrfile();
+    }
+
+    objfile = new File(objfilename);
+    bcfile = new File(bcfilename);
+    llfile = new File(llfilename);
+    symfile = new File(symfilename);
+}
+
+void Module::setDocfile()
+{
+    FileName *docfilename;
+    char *argdoc;
+
+    if (global.params.docname)
+	argdoc = global.params.docname;
+    else if (global.params.preservePaths)
+	argdoc = (char *)arg;
+    else
+	argdoc = FileName::name((char *)arg);
+    if (!FileName::absolute(argdoc))
+    {	//FileName::ensurePathExists(global.params.docdir);
+	argdoc = FileName::combine(global.params.docdir, argdoc);
+    }
+    if (global.params.docname)
+	docfilename = new FileName(argdoc, 0);
+    else
+	docfilename = FileName::forceExt(argdoc, global.doc_ext);
+
+    if (docfilename->equals(srcfile->name))
+    {   error("Source file and documentation file have same name '%s'", srcfile->name->str);
+	fatal();
+    }
+
+    docfile = new File(docfilename);
+}
+
+void Module::setHdrfile()
+{
+    FileName *hdrfilename;
+    char *arghdr;
+
+    if (global.params.hdrname)
+	arghdr = global.params.hdrname;
+    else if (global.params.preservePaths)
+	arghdr = (char *)arg;
+    else
+	arghdr = FileName::name((char *)arg);
+    if (!FileName::absolute(arghdr))
+    {	//FileName::ensurePathExists(global.params.hdrdir);
+	arghdr = FileName::combine(global.params.hdrdir, arghdr);
+    }
+    if (global.params.hdrname)
+	hdrfilename = new FileName(arghdr, 0);
+    else
+	hdrfilename = FileName::forceExt(arghdr, global.hdr_ext);
+
+    if (hdrfilename->equals(srcfile->name))
+    {   error("Source file and 'header' file have same name '%s'", srcfile->name->str);
+	fatal();
+    }
+
+    hdrfile = new File(hdrfilename);
+}
+
+void Module::deleteObjFile()
+{
+    if (global.params.obj)
+	objfile->remove();
+    //if (global.params.llvmBC)
+    bcfile->remove();
+    if (docfile)
+	docfile->remove();
+}
+
+Module::~Module()
+{
+}
+
+const char *Module::kind()
+{
+    return "module";
+}
+
+Module *Module::load(Loc loc, Array *packages, Identifier *ident)
+{   Module *m;
+    char *filename;
+
+    //printf("Module::load(ident = '%s')\n", ident->toChars());
+
+    // Build module filename by turning:
+    //	foo.bar.baz
+    // into:
+    //	foo\bar\baz
+    filename = ident->toChars();
+    if (packages && packages->dim)
+    {
+	OutBuffer buf;
+	int i;
+
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+
+	    buf.writestring(pid->toChars());
+#if _WIN32
+	    buf.writeByte('\\');
+#else
+	    buf.writeByte('/');
+#endif
+	}
+	buf.writestring(filename);
+	buf.writeByte(0);
+	filename = (char *)buf.extractData();
+    }
+
+    m = new Module(filename, ident, 0, 0);
+    m->loc = loc;
+
+    /* Search along global.path for .di file, then .d file.
+     */
+    char *result = NULL;
+    FileName *fdi = FileName::forceExt(filename, global.hdr_ext);
+    FileName *fd  = FileName::forceExt(filename, global.mars_ext);
+    char *sdi = fdi->toChars();
+    char *sd  = fd->toChars();
+
+    if (FileName::exists(sdi))
+	result = sdi;
+    else if (FileName::exists(sd))
+	result = sd;
+    else if (FileName::absolute(filename))
+	;
+    else if (!global.path)
+	;
+    else
+    {
+	for (size_t i = 0; i < global.path->dim; i++)
+	{
+	    char *p = (char *)global.path->data[i];
+	    char *n = FileName::combine(p, sdi);
+	    if (FileName::exists(n))
+	    {	result = n;
+		break;
+	    }
+	    mem.free(n);
+	    n = FileName::combine(p, sd);
+	    if (FileName::exists(n))
+	    {	result = n;
+		break;
+	    }
+	    mem.free(n);
+	}
+    }
+    if (result)
+	m->srcfile = new File(result);
+
+    if (global.params.verbose)
+    {
+	printf("import    ");
+	if (packages)
+	{
+	    for (size_t i = 0; i < packages->dim; i++)
+	    {   Identifier *pid = (Identifier *)packages->data[i];
+		printf("%s.", pid->toChars());
+	    }
+	}
+	printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars());
+    }
+
+    m->read(loc);
+    m->parse();
+
+#ifdef IN_GCC
+    d_gcc_magic_module(m);
+#endif
+
+    return m;
+}
+
+void Module::read(Loc loc)
+{
+    //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
+    if (srcfile->read())
+    {	error(loc, "cannot read file '%s'", srcfile->toChars());
+	fatal();
+    }
+}
+
+inline unsigned readwordLE(unsigned short *p)
+{
+#if __I86__
+    return *p;
+#else
+    return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0];
+#endif
+}
+
+inline unsigned readwordBE(unsigned short *p)
+{
+    return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1];
+}
+
+inline unsigned readlongLE(unsigned *p)
+{
+#if __I86__
+    return *p;
+#else
+    return ((unsigned char *)p)[0] |
+	(((unsigned char *)p)[1] << 8) |
+	(((unsigned char *)p)[2] << 16) |
+	(((unsigned char *)p)[3] << 24);
+#endif
+}
+
+inline unsigned readlongBE(unsigned *p)
+{
+    return ((unsigned char *)p)[3] |
+	(((unsigned char *)p)[2] << 8) |
+	(((unsigned char *)p)[1] << 16) |
+	(((unsigned char *)p)[0] << 24);
+}
+
+#if IN_GCC
+void Module::parse(bool dump_source)
+#else
+void Module::parse()
+#endif
+{   char *srcname;
+    unsigned char *buf;
+    unsigned buflen;
+    unsigned le;
+    unsigned bom;
+
+    //printf("Module::parse()\n");
+
+    srcname = srcfile->name->toChars();
+    //printf("Module::parse(srcname = '%s')\n", srcname);
+
+    buf = srcfile->buffer;
+    buflen = srcfile->len;
+
+    if (buflen >= 2)
+    {
+	/* Convert all non-UTF-8 formats to UTF-8.
+	 * BOM : http://www.unicode.org/faq/utf_bom.html
+	 * 00 00 FE FF	UTF-32BE, big-endian
+	 * FF FE 00 00	UTF-32LE, little-endian
+	 * FE FF	UTF-16BE, big-endian
+	 * FF FE	UTF-16LE, little-endian
+	 * EF BB BF	UTF-8
+	 */
+
+	bom = 1;		// assume there's a BOM
+	if (buf[0] == 0xFF && buf[1] == 0xFE)
+	{
+	    if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
+	    {	// UTF-32LE
+		le = 1;
+
+	    Lutf32:
+		OutBuffer dbuf;
+		unsigned *pu = (unsigned *)(buf);
+		unsigned *pumax = &pu[buflen / 4];
+
+		if (buflen & 3)
+		{   error("odd length of UTF-32 char source %u", buflen);
+		    fatal();
+		}
+
+		dbuf.reserve(buflen / 4);
+		for (pu += bom; pu < pumax; pu++)
+		{   unsigned u;
+
+		    u = le ? readlongLE(pu) : readlongBE(pu);
+		    if (u & ~0x7F)
+		    {
+			if (u > 0x10FFFF)
+			{   error("UTF-32 value %08x greater than 0x10FFFF", u);
+			    fatal();
+			}
+			dbuf.writeUTF8(u);
+		    }
+		    else
+			dbuf.writeByte(u);
+		}
+		dbuf.writeByte(0);		// add 0 as sentinel for scanner
+		buflen = dbuf.offset - 1;	// don't include sentinel in count
+		buf = (unsigned char *) dbuf.extractData();
+	    }
+	    else
+	    {   // UTF-16LE (X86)
+		// Convert it to UTF-8
+		le = 1;
+
+	    Lutf16:
+		OutBuffer dbuf;
+		unsigned short *pu = (unsigned short *)(buf);
+		unsigned short *pumax = &pu[buflen / 2];
+
+		if (buflen & 1)
+		{   error("odd length of UTF-16 char source %u", buflen);
+		    fatal();
+		}
+
+		dbuf.reserve(buflen / 2);
+		for (pu += bom; pu < pumax; pu++)
+		{   unsigned u;
+
+		    u = le ? readwordLE(pu) : readwordBE(pu);
+		    if (u & ~0x7F)
+		    {	if (u >= 0xD800 && u <= 0xDBFF)
+			{   unsigned u2;
+
+			    if (++pu > pumax)
+			    {   error("surrogate UTF-16 high value %04x at EOF", u);
+				fatal();
+			    }
+			    u2 = le ? readwordLE(pu) : readwordBE(pu);
+			    if (u2 < 0xDC00 || u2 > 0xDFFF)
+			    {   error("surrogate UTF-16 low value %04x out of range", u2);
+				fatal();
+			    }
+			    u = (u - 0xD7C0) << 10;
+			    u |= (u2 - 0xDC00);
+			}
+			else if (u >= 0xDC00 && u <= 0xDFFF)
+			{   error("unpaired surrogate UTF-16 value %04x", u);
+			    fatal();
+			}
+			else if (u == 0xFFFE || u == 0xFFFF)
+			{   error("illegal UTF-16 value %04x", u);
+			    fatal();
+			}
+			dbuf.writeUTF8(u);
+		    }
+		    else
+			dbuf.writeByte(u);
+		}
+		dbuf.writeByte(0);		// add 0 as sentinel for scanner
+		buflen = dbuf.offset - 1;	// don't include sentinel in count
+		buf = (unsigned char *) dbuf.extractData();
+	    }
+	}
+	else if (buf[0] == 0xFE && buf[1] == 0xFF)
+	{   // UTF-16BE
+	    le = 0;
+	    goto Lutf16;
+	}
+	else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+	{   // UTF-32BE
+	    le = 0;
+	    goto Lutf32;
+	}
+	else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+	{   // UTF-8
+
+	    buf += 3;
+	    buflen -= 3;
+	}
+	else
+	{
+	    /* There is no BOM. Make use of Arcane Jill's insight that
+	     * the first char of D source must be ASCII to
+	     * figure out the encoding.
+	     */
+
+	    bom = 0;
+	    if (buflen >= 4)
+	    {   if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+		{   // UTF-32LE
+		    le = 1;
+		    goto Lutf32;
+		}
+		else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+		{   // UTF-32BE
+		    le = 0;
+		    goto Lutf32;
+		}
+	    }
+	    if (buflen >= 2)
+	    {
+		if (buf[1] == 0)
+		{   // UTF-16LE
+		    le = 1;
+		    goto Lutf16;
+		}
+		else if (buf[0] == 0)
+		{   // UTF-16BE
+		    le = 0;
+		    goto Lutf16;
+		}
+	    }
+
+	    // It's UTF-8
+	    if (buf[0] >= 0x80)
+	    {	error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+		fatal();
+	    }
+	}
+    }
+
+#ifdef IN_GCC
+    // dump utf-8 encoded source
+    if (dump_source)
+    {	// %% srcname could contain a path ...
+	d_gcc_dump_source(srcname, "utf-8", buf, buflen);
+    }
+#endif
+
+    /* If it starts with the string "Ddoc", then it's a documentation
+     * source file.
+     */
+    if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
+    {
+	comment = buf + 4;
+	isDocFile = 1;
+	if (!docfile)
+	    setDocfile();
+	return;
+    }
+    if (isHtml)
+    {
+	OutBuffer *dbuf = new OutBuffer();
+	Html h(srcname, buf, buflen);
+	h.extractCode(dbuf);
+	buf = dbuf->data;
+	buflen = dbuf->offset;
+#ifdef IN_GCC
+	// dump extracted source
+	if (dump_source)
+	    d_gcc_dump_source(srcname, "d.utf-8", buf, buflen);
+#endif
+    }
+    Parser p(this, buf, buflen, docfile != NULL);
+    p.nextToken();
+    members = p.parseModule();
+    md = p.md;
+    numlines = p.loc.linnum;
+
+    DsymbolTable *dst;
+
+    if (md)
+    {	this->ident = md->id;
+	dst = Package::resolve(md->packages, &this->parent, NULL);
+    }
+    else
+    {
+	dst = modules;
+
+	/* Check to see if module name is a valid identifier
+	 */
+	if (!Lexer::isValidIdentifier(this->ident->toChars()))
+	    error("has non-identifier characters in filename, use module declaration instead");
+    }
+
+    // Update global list of modules
+    if (!dst->insert(this))
+    {
+	if (md)
+	    error(loc, "is in multiple packages %s", md->toChars());
+	else
+	    error(loc, "is in multiple defined");
+    }
+    else
+    {
+	amodules.push(this);
+    }
+}
+
+void Module::semantic()
+{   int i;
+
+    if (semanticstarted)
+	return;
+
+    //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+    semanticstarted = 1;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+
+    //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
+
+    // Add import of "object" if this module isn't "object"
+    if (ident != Id::object)
+    {
+	Import *im = new Import(0, NULL, Id::object, NULL, 0);
+	members->shift(im);
+    }
+
+    // Add all symbols into module's symbol table
+    symtab = new DsymbolTable();
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->addMember(NULL, sc->scopesym, 1);
+    }
+
+    // Pass 1 semantic routines: do public side of the definition
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
+	s->semantic(sc);
+	runDeferredSemantic();
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+    //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+}
+
+void Module::semantic2()
+{   int i;
+
+    if (deferred.dim)
+    {
+	for (int i = 0; i < deferred.dim; i++)
+	{
+	    Dsymbol *sd = (Dsymbol *)deferred.data[i];
+
+	    sd->error("unable to resolve forward reference in definition");
+	}
+	return;
+    }
+    //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+    if (semanticstarted >= 2)
+	return;
+    assert(semanticstarted == 1);
+    semanticstarted = 2;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 2 semantic routines: do initializers and function bodies
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->semantic2(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+    //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+}
+
+void Module::semantic3()
+{   int i;
+
+    //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
+    if (semanticstarted >= 3)
+	return;
+    assert(semanticstarted == 2);
+    semanticstarted = 3;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 3 semantic routines: do initializers and function bodies
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
+	s->semantic3(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+}
+
+void Module::inlineScan()
+{   int i;
+
+    if (semanticstarted >= 4)
+	return;
+    assert(semanticstarted == 3);
+    semanticstarted = 4;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    //printf("Module = %p\n", sc.scopesym);
+
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//if (global.params.verbose)
+	    //printf("inline scan symbol %s\n", s->toChars());
+
+	s->inlineScan();
+    }
+    semanticdone = semanticstarted;
+}
+
+/****************************************************
+ */
+
+void Module::gensymfile()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+
+    //printf("Module::gensymfile()\n");
+
+    buf.printf("// Sym file generated from '%s'", srcfile->toChars());
+    buf.writenl();
+
+    for (int i = 0; i < members->dim; i++)
+    {	Dsymbol *s = (Dsymbol *)members->data[i];
+
+	s->toCBuffer(&buf, &hgs);
+    }
+
+    // Transfer image to file
+    symfile->setbuffer(buf.data, buf.offset);
+    buf.data = NULL;
+
+    symfile->writev();
+}
+
+/**********************************
+ * Determine if we need to generate an instance of ModuleInfo
+ * for this Module.
+ */
+
+int Module::needModuleInfo()
+{
+    return needmoduleinfo || global.params.cov;
+}
+
+Dsymbol *Module::search(Loc loc, Identifier *ident, int flags)
+{
+    /* Since modules can be circularly referenced,
+     * need to stop infinite recursive searches.
+     */
+
+    //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
+    Dsymbol *s;
+    if (insearch)
+	s = NULL;
+    else if (searchCacheIdent == ident && searchCacheFlags == flags)
+	s = searchCacheSymbol;
+    else
+    {
+	insearch = 1;
+	s = ScopeDsymbol::search(loc, ident, flags);
+	insearch = 0;
+
+	searchCacheIdent = ident;
+	searchCacheSymbol = s;
+	searchCacheFlags = flags;
+    }
+    return s;
+}
+
+/*******************************************
+ * Can't run semantic on s now, try again later.
+ */
+
+void Module::addDeferredSemantic(Dsymbol *s)
+{
+    // Don't add it if it is already there
+    for (int i = 0; i < deferred.dim; i++)
+    {
+	Dsymbol *sd = (Dsymbol *)deferred.data[i];
+
+	if (sd == s)
+	    return;
+    }
+
+    //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
+    deferred.push(s);
+}
+
+
+/******************************************
+ * Run semantic() on deferred symbols.
+ */
+
+void Module::runDeferredSemantic()
+{
+    size_t len;
+
+    static int nested;
+    if (nested)
+	return;
+    //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+    nested++;
+
+    do
+    {
+	dprogress = 0;
+	len = deferred.dim;
+	if (!len)
+	    break;
+
+	Dsymbol **todo;
+	Dsymbol *tmp;
+	if (len == 1)
+	{
+	    todo = &tmp;
+	}
+	else
+	{
+	    todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *));
+	    assert(todo);
+	}
+	memcpy(todo, deferred.data, len * sizeof(Dsymbol *));
+	deferred.setDim(0);
+
+	for (int i = 0; i < len; i++)
+	{
+	    Dsymbol *s = todo[i];
+
+	    s->semantic(NULL);
+	    //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
+	}
+	//printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+    } while (deferred.dim < len || dprogress);	// while making progress
+    nested--;
+    //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+}
+
+/* =========================== ModuleDeclaration ===================== */
+
+ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id)
+{
+    this->packages = packages;
+    this->id = id;
+}
+
+char *ModuleDeclaration::toChars()
+{
+    OutBuffer buf;
+    int i;
+
+    if (packages && packages->dim)
+    {
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+
+	    buf.writestring(pid->toChars());
+	    buf.writeByte('.');
+	}
+    }
+    buf.writestring(id->toChars());
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+/* =========================== Package ===================== */
+
+Package::Package(Identifier *ident)
+	: ScopeDsymbol(ident)
+{
+}
+
+
+const char *Package::kind()
+{
+    return "package";
+}
+
+
+DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg)
+{
+    DsymbolTable *dst = Module::modules;
+    Dsymbol *parent = NULL;
+
+    //printf("Package::resolve()\n");
+    if (ppkg)
+	*ppkg = NULL;
+
+    if (packages)
+    {   int i;
+
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+	    Dsymbol *p;
+
+	    p = dst->lookup(pid);
+	    if (!p)
+	    {
+		p = new Package(pid);
+		dst->insert(p);
+		p->parent = parent;
+		((ScopeDsymbol *)p)->symtab = new DsymbolTable();
+	    }
+	    else
+	    {
+		assert(p->isPackage());
+		if (p->isModule())
+		{   p->error("module and package have the same name");
+		    fatal();
+		    break;
+		}
+	    }
+	    parent = p;
+	    dst = ((Package *)p)->symtab;
+	    if (ppkg && !*ppkg)
+		*ppkg = (Package *)p;
+	}
+	if (pparent)
+	{
+	    *pparent = parent;
+	}
+    }
+    return dst;
+}
--- a/dmd/module.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/module.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,185 +1,187 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2005 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#ifndef DMD_MODULE_H
-#define DMD_MODULE_H
-
-#ifdef __DMC__
-#pragma once
-#endif /* __DMC__ */
-
-#include "root.h"
-#include "dsymbol.h"
-
-struct ModuleInfoDeclaration;
-struct ClassDeclaration;
-struct ModuleDeclaration;
-struct Macro;
-struct Escape;
-struct VarDeclaration;
-
-// Back end
-#if IN_LLVM
-struct DValue;
-typedef DValue elem;
-#else
-#ifdef IN_GCC
-union tree_node; typedef union tree_node elem;
-#else
-struct elem;
-#endif
-#endif
-
-struct Package : ScopeDsymbol
-{
-    Package(Identifier *ident);
-    char *kind();
-
-    static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg);
-
-    Package *isPackage() { return this; }
-
-    virtual void semantic(Scope *sc) { }
-};
-
-struct Module : Package
-{
-    static Module *rootModule;
-    static DsymbolTable *modules;	// symbol table of all modules
-    static Array amodules;		// array of all modules
-    static Array deferred;	// deferred Dsymbol's needing semantic() run on them
-    static unsigned dprogress;	// progress resolving the deferred list
-    static void init();
-
-    static ClassDeclaration *moduleinfo;
-
-
-    const char *arg;	// original argument name
-    ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
-    File *srcfile;	// input source file
-    File *objfile;	// output .obj file
-    File *bcfile;  // output .bc file
-    File *llfile;  // output .ll file
-    File *hdrfile;	// 'header' file
-    File *symfile;	// output symbol file
-    File *docfile;	// output documentation file
-    unsigned errors;	// if any errors in file
-    unsigned numlines;	// number of lines in source file
-    int isHtml;		// if it is an HTML file
-    int isDocFile;	// if it is a documentation input file, not D source
-    int needmoduleinfo;
-#ifdef IN_GCC
-    int strictlyneedmoduleinfo;
-#endif
-
-    int insearch;
-    Identifier *searchCacheIdent;
-    Dsymbol *searchCacheSymbol;	// cached value of search
-    int searchCacheFlags;	// cached flags
-
-    int semanticstarted;	// has semantic() been started?
-    int semanticdone;		// has semantic() been done?
-    int root;			// != 0 if this is a 'root' module,
-				// i.e. a module that will be taken all the
-				// way to an object file
-    Module *importedFrom;	// module from command line we're imported from,
-				// i.e. a module that will be taken all the
-				// way to an object file
-
-    Array *decldefs;		// top level declarations for this Module
-
-    Array aimports;		// all imported modules
-
-    ModuleInfoDeclaration *vmoduleinfo;
-
-    unsigned debuglevel;	// debug level
-    Array *debugids;		// debug identifiers
-    Array *debugidsNot;		// forward referenced debug identifiers
-
-    unsigned versionlevel;	// version level
-    Array *versionids;		// version identifiers
-    Array *versionidsNot;	// forward referenced version identifiers
-
-    Macro *macrotable;		// document comment macros
-    Escape *escapetable;	// document comment escapes
-
-    Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen);
-    ~Module();
-
-    static Module *load(Loc loc, Array *packages, Identifier *ident);
-
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
-    void setDocfile();	// set docfile member
-    void read(Loc loc);	// read file
-#if IN_GCC
-    void parse(bool dump_source = false);	// syntactic parse
-#else
-    void parse();	// syntactic parse
-#endif
-    void semantic();	// semantic analysis
-    void semantic2();	// pass 2 semantic analysis
-    void semantic3();	// pass 3 semantic analysis
-    void inlineScan();	// scan for functions to inline
-    void setHdrfile();	// set hdrfile member
-#ifdef _DH
-    void genhdrfile();  // generate D import file
-#endif
-    void genobjfile();
-    void gensymfile();
-    void gendocfile();
-    int needModuleInfo();
-    Dsymbol *search(Loc loc, Identifier *ident, int flags);
-    void deleteObjFile();
-    void addDeferredSemantic(Dsymbol *s);
-    void runDeferredSemantic();
-
-    // Back end
-
-    Symbol *cov;		// private uint[] __coverage;
-    unsigned *covb;		// bit array of valid code line numbers
-
-    Symbol *sictor;		// module order independent constructor
-    Symbol *sctor;		// module constructor
-    Symbol *sdtor;		// module destructor
-    Symbol *stest;		// module unit test
-
-    Symbol *sfilename;		// symbol for filename
-
-    Symbol *massert;		// module assert function
-    Symbol *toModuleAssert();	// get module assert function
-
-    Symbol *marray;		// module array bounds function
-    Symbol *toModuleArray();	// get module array bounds function
-
-
-    static Symbol *gencritsec();
-    elem *toEfilename();
-    elem *toEmodulename();
-
-    Symbol *toSymbol();
-    void genmoduleinfo();
-
-    // LLVMDC
-    Module *isModule() { return this; }
-};
-
-
-struct ModuleDeclaration
-{
-    Identifier *id;
-    Array *packages;		// array of Identifier's representing packages
-
-    ModuleDeclaration(Array *packages, Identifier *id);
-
-    char *toChars();
-};
-
-#endif /* DMD_MODULE_H */
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_MODULE_H
+#define DMD_MODULE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+struct ModuleInfoDeclaration;
+struct ClassDeclaration;
+struct ModuleDeclaration;
+struct Macro;
+struct Escape;
+struct VarDeclaration;
+struct Library;
+
+// Back end
+#if IN_LLVM
+struct DValue;
+typedef DValue elem;
+#else
+#ifdef IN_GCC
+union tree_node; typedef union tree_node elem;
+#else
+struct elem;
+#endif
+#endif
+
+struct Package : ScopeDsymbol
+{
+    Package(Identifier *ident);
+    const char *kind();
+
+    static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg);
+
+    Package *isPackage() { return this; }
+
+    virtual void semantic(Scope *sc) { }
+};
+
+struct Module : Package
+{
+    static Module *rootModule;
+    static DsymbolTable *modules;	// symbol table of all modules
+    static Array amodules;		// array of all modules
+    static Array deferred;	// deferred Dsymbol's needing semantic() run on them
+    static unsigned dprogress;	// progress resolving the deferred list
+    static void init();
+
+    static ClassDeclaration *moduleinfo;
+
+
+    const char *arg;	// original argument name
+    ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
+    File *srcfile;	// input source file
+    File *objfile;	// output .obj file
+    File *bcfile;  // output .bc file
+    File *llfile;  // output .ll file
+    File *hdrfile;	// 'header' file
+    File *symfile;	// output symbol file
+    File *docfile;	// output documentation file
+    unsigned errors;	// if any errors in file
+    unsigned numlines;	// number of lines in source file
+    int isHtml;		// if it is an HTML file
+    int isDocFile;	// if it is a documentation input file, not D source
+    int needmoduleinfo;
+#ifdef IN_GCC
+    int strictlyneedmoduleinfo;
+#endif
+
+    int insearch;
+    Identifier *searchCacheIdent;
+    Dsymbol *searchCacheSymbol;	// cached value of search
+    int searchCacheFlags;	// cached flags
+
+    int semanticstarted;	// has semantic() been started?
+    int semanticdone;		// has semantic() been done?
+    int root;			// != 0 if this is a 'root' module,
+				// i.e. a module that will be taken all the
+				// way to an object file
+    Module *importedFrom;	// module from command line we're imported from,
+				// i.e. a module that will be taken all the
+				// way to an object file
+
+    Array *decldefs;		// top level declarations for this Module
+
+    Array aimports;		// all imported modules
+
+    ModuleInfoDeclaration *vmoduleinfo;
+
+    unsigned debuglevel;	// debug level
+    Array *debugids;		// debug identifiers
+    Array *debugidsNot;		// forward referenced debug identifiers
+
+    unsigned versionlevel;	// version level
+    Array *versionids;		// version identifiers
+    Array *versionidsNot;	// forward referenced version identifiers
+
+    Macro *macrotable;		// document comment macros
+    Escape *escapetable;	// document comment escapes
+
+    Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+    ~Module();
+
+    static Module *load(Loc loc, Array *packages, Identifier *ident);
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    const char *kind();
+    void setDocfile();	// set docfile member
+    void read(Loc loc);	// read file
+#if IN_GCC
+    void parse(bool dump_source = false);	// syntactic parse
+#else
+    void parse();	// syntactic parse
+#endif
+    void semantic();	// semantic analysis
+    void semantic2();	// pass 2 semantic analysis
+    void semantic3();	// pass 3 semantic analysis
+    void inlineScan();	// scan for functions to inline
+    void setHdrfile();	// set hdrfile member
+#ifdef _DH
+    void genhdrfile();  // generate D import file
+#endif
+    void genobjfile(int multiobj);
+    void gensymfile();
+    void gendocfile();
+    int needModuleInfo();
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    void deleteObjFile();
+    void addDeferredSemantic(Dsymbol *s);
+    void runDeferredSemantic();
+
+    // Back end
+
+    int doppelganger;		// sub-module
+    Symbol *cov;		// private uint[] __coverage;
+    unsigned *covb;		// bit array of valid code line numbers
+
+    Symbol *sictor;		// module order independent constructor
+    Symbol *sctor;		// module constructor
+    Symbol *sdtor;		// module destructor
+    Symbol *stest;		// module unit test
+
+    Symbol *sfilename;		// symbol for filename
+
+    Symbol *massert;		// module assert function
+    Symbol *toModuleAssert();	// get module assert function
+
+    Symbol *marray;		// module array bounds function
+    Symbol *toModuleArray();	// get module array bounds function
+
+
+    static Symbol *gencritsec();
+    elem *toEfilename();
+    elem *toEmodulename();
+
+    Symbol *toSymbol();
+    void genmoduleinfo();
+
+    // LLVMDC
+    Module *isModule() { return this; }
+};
+
+
+struct ModuleDeclaration
+{
+    Identifier *id;
+    Array *packages;		// array of Identifier's representing packages
+
+    ModuleDeclaration(Array *packages, Identifier *id);
+
+    char *toChars();
+};
+
+#endif /* DMD_MODULE_H */
--- a/dmd/mtype.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/mtype.c	Sat Jul 12 19:38:31 2008 +0200
@@ -115,7 +115,7 @@
     this->mod = 0;
     this->next = next;
     this->deco = NULL;
-#if V2
+#if DMDV2
     this->cto = NULL;
     this->ito = NULL;
 #endif
@@ -2226,6 +2226,35 @@
     return merge();
 }
 
+void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    //printf("TypeAArray::resolve() %s\n", toChars());
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+    {
+	Expression *e;
+	Type *t;
+	Dsymbol *s;
+
+	index->resolve(loc, sc, &e, &t, &s);
+	if (e)
+	{   // It was an expression -
+	    // Rewrite as a static array
+
+	    TypeSArray *tsa = new TypeSArray(next, e);
+	    return tsa->resolve(loc, sc, pe, pt, ps);
+	}
+	else if (t)
+	    index = t;
+	else
+	    index->error(loc, "index is not a type or an expression");
+    }
+    Type::resolve(loc, sc, pe, pt, ps);
+}
+
+
 Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
 {
 #if LOGDOTEXP
@@ -3151,6 +3180,7 @@
     if (s)
     {
 	//printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	s->checkDeprecated(loc, sc);		// check for deprecated aliases
 	s = s->toAlias();
 	//printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
 	for (i = 0; i < idents.dim; i++)
@@ -3548,7 +3578,7 @@
 {
     Type *t;
 
-    t = semantic(0, sc);
+    t = semantic(loc, sc);
     if (t == this)
 	return NULL;
     return t->toDsymbol(sc);
@@ -3624,6 +3654,10 @@
 	sc->intypeof++;
 	exp = exp->semantic(sc);
 	sc->intypeof--;
+	if (exp->op == TOKtype)
+	{
+	    error(loc, "argument %s to typeof is not an expression", exp->toChars());
+	}
 	t = exp->type;
 	if (!t)
 	{
@@ -4174,6 +4208,7 @@
     {
 	/* Create a TupleExp
 	 */
+	e = e->semantic(sc);	// do this before turning on noaccesscheck
 	Expressions *exps = new Expressions;
 	exps->reserve(sym->fields.dim);
 	for (size_t i = 0; i < sym->fields.dim; i++)
@@ -4182,7 +4217,10 @@
 	    exps->push(fe);
 	}
 	e = new TupleExp(e->loc, exps);
+	sc = sc->push();
+	sc->noaccesscheck = 1;
 	e = e->semantic(sc);
+	sc->pop();
 	return e;
     }
 
@@ -4206,6 +4244,8 @@
 	//return getProperty(e->loc, ident);
 	return Type::dotExp(sc, e, ident);
     }
+    if (!s->isFuncDeclaration())	// because of overloading
+	s->checkDeprecated(e->loc, sc);
     s = s->toAlias();
 
     v = s->isVarDeclaration();
@@ -4459,6 +4499,7 @@
     {
 	/* Create a TupleExp
 	 */
+	e = e->semantic(sc);	// do this before turning on noaccesscheck
 	Expressions *exps = new Expressions;
 	exps->reserve(sym->fields.dim);
 	for (size_t i = 0; i < sym->fields.dim; i++)
@@ -4467,7 +4508,10 @@
 	    exps->push(fe);
 	}
 	e = new TupleExp(e->loc, exps);
+	sc = sc->push();
+	sc->noaccesscheck = 1;
 	e = e->semantic(sc);
+	sc->pop();
 	return e;
     }
 
@@ -4541,6 +4585,7 @@
             e = new PtrExp(e->loc, e);
             e->type = ct->next->next->next;
         }
+        }
 
 #else
 
@@ -4565,9 +4610,31 @@
 		    e->type = t->pointerTo();
 		}
 		e = new PtrExp(e->loc, e, t);
-
-#endif
-	    }
+        }
+
+#endif // !LLVMDC
+
+	    return e;
+	}
+
+	if (ident == Id::__vptr)
+	{   /* The pointer to the vtbl[]
+	     * *cast(void***)e
+	     */
+	    e = e->castTo(sc, tvoidptr->pointerTo()->pointerTo());
+	    e = new PtrExp(e->loc, e);
+	    e = e->semantic(sc);
+	    return e;
+	}
+
+	if (ident == Id::__monitor)
+	{   /* The handle to the monitor (call it a void*)
+	     * *(cast(void**)e + 1)
+	     */
+	    e = e->castTo(sc, tvoidptr->pointerTo());
+	    e = new AddExp(e->loc, e, new IntegerExp(1));
+	    e = new PtrExp(e->loc, e);
+	    e = e->semantic(sc);
 	    return e;
 	}
 
@@ -4587,6 +4654,8 @@
 	    return Type::dotExp(sc, e, ident);
 	}
     }
+    if (!s->isFuncDeclaration())	// because of overloading
+	s->checkDeprecated(e->loc, sc);
     s = s->toAlias();
     v = s->isVarDeclaration();
     if (v && v->isConst())
--- a/dmd/mtype.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/mtype.h	Sat Jul 12 19:38:31 2008 +0200
@@ -355,6 +355,7 @@
     Type *syntaxCopy();
     d_uns64 size(Loc loc);
     Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
     void toDecoBuffer(OutBuffer *buf);
     void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
     Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
--- a/dmd/optimize.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/optimize.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,752 +1,752 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <ctype.h>
-#include <assert.h>
-#include <math.h>
-
-#if __DMC__
-#include <complex.h>
-#endif
-
-#include "lexer.h"
-#include "mtype.h"
-#include "expression.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "init.h"
-
-
-#ifdef IN_GCC
-#include "d-gcc-real.h"
-
-/* %% fix? */
-extern "C" bool real_isnan (const real_t *);
-#endif
-
-static real_t zero;	// work around DMC bug for now
-
-
-/*************************************
- * If expression is a variable with a const initializer,
- * return that initializer.
- */
-
-Expression *fromConstInitializer(Expression *e1)
-{
-    //printf("fromConstInitializer(%s)\n", e1->toChars());
-    if (e1->op == TOKvar)
-    {	VarExp *ve = (VarExp *)e1;
-	VarDeclaration *v = ve->var->isVarDeclaration();
-	if (v && v->isConst() && v->init)
-	{   Expression *ei = v->init->toExpression();
-	    if (ei && ei->type)
-		e1 = ei;
-	}
-    }
-    return e1;
-}
-
-
-Expression *Expression::optimize(int result)
-{
-    //printf("Expression::optimize(result = x%x) %s\n", result, toChars());
-    return this;
-}
-
-Expression *VarExp::optimize(int result)
-{
-    if (result & WANTinterpret)
-    {
-	return fromConstInitializer(this);
-    }
-    return this;
-}
-
-Expression *TupleExp::optimize(int result)
-{
-    for (size_t i = 0; i < exps->dim; i++)
-    {   Expression *e = (Expression *)exps->data[i];
-
-	e = e->optimize(WANTvalue | (result & WANTinterpret));
-	exps->data[i] = (void *)e;
-    }
-    return this;
-}
-
-Expression *ArrayLiteralExp::optimize(int result)
-{
-    if (elements)
-    {
-	for (size_t i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-
-	    e = e->optimize(WANTvalue | (result & WANTinterpret));
-	    elements->data[i] = (void *)e;
-	}
-    }
-    return this;
-}
-
-Expression *AssocArrayLiteralExp::optimize(int result)
-{
-    assert(keys->dim == values->dim);
-    for (size_t i = 0; i < keys->dim; i++)
-    {   Expression *e = (Expression *)keys->data[i];
-
-	e = e->optimize(WANTvalue | (result & WANTinterpret));
-	keys->data[i] = (void *)e;
-
-	e = (Expression *)values->data[i];
-	e = e->optimize(WANTvalue | (result & WANTinterpret));
-	values->data[i] = (void *)e;
-    }
-    return this;
-}
-
-Expression *StructLiteralExp::optimize(int result)
-{
-    if (elements)
-    {
-	for (size_t i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    if (!e)
-		continue;
-	    e = e->optimize(WANTvalue | (result & WANTinterpret));
-	    elements->data[i] = (void *)e;
-	}
-    }
-    return this;
-}
-
-Expression *TypeExp::optimize(int result)
-{
-    return this;
-}
-
-Expression *UnaExp::optimize(int result)
-{
-    e1 = e1->optimize(result);
-    return this;
-}
-
-Expression *NegExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    if (e1->isConst() == 1)
-    {
-	e = Neg(type, e1);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *ComExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    if (e1->isConst() == 1)
-    {
-	e = Com(type, e1);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *NotExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    if (e1->isConst() == 1)
-    {
-	e = Not(type, e1);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *BoolExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    if (e1->isConst() == 1)
-    {
-	e = Bool(type, e1);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *AddrExp::optimize(int result)
-{   Expression *e;
-
-    //printf("AddrExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(result);
-    // Convert &*ex to ex
-    if (e1->op == TOKstar)
-    {	Expression *ex;
-
-	ex = ((PtrExp *)e1)->e1;
-	if (type->equals(ex->type))
-	    e = ex;
-	else
-	{
-	    e = ex->copy();
-	    e->type = type;
-	}
-	return e;
-    }
-#if !IN_LLVM
-    if (e1->op == TOKvar)
-    {	VarExp *ve = (VarExp *)e1;
-	if (!ve->var->isOut() && !ve->var->isRef() &&
-	    !ve->var->isImportedSymbol())
-	{
-	    e = new SymOffExp(loc, ve->var, 0);
-	    e->type = type;
-	    return e;
-	}
-    }
-    if (e1->op == TOKindex)
-    {	// Convert &array[n] to &array+n
-	IndexExp *ae = (IndexExp *)e1;
-
-	if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
-	{
-	    integer_t index = ae->e2->toInteger();
-	    VarExp *ve = (VarExp *)ae->e1;
-	    if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit
-		&& !ve->var->isImportedSymbol())
-	    {
-		TypeSArray *ts = (TypeSArray *)ve->type;
-		integer_t dim = ts->dim->toInteger();
-		if (index < 0 || index >= dim)
-		    error("array index %lld is out of bounds [0..%lld]", index, dim);
-		e = new SymOffExp(loc, ve->var, index * ts->next->size());
-		e->type = type;
-		return e;
-	    }
-	}
-    }
-#endif
-    return this;
-}
-
-Expression *PtrExp::optimize(int result)
-{
-    //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars());
-    e1 = e1->optimize(result);
-    // Convert *&ex to ex
-    if (e1->op == TOKaddress)
-    {	Expression *e;
-	Expression *ex;
-
-	ex = ((AddrExp *)e1)->e1;
-	if (type->equals(ex->type))
-	    e = ex;
-	else
-	{
-	    e = ex->copy();
-	    e->type = type;
-	}
-	return e;
-    }
-    // Constant fold *(&structliteral + offset)
-    if (e1->op == TOKadd)
-    {
-	Expression *e;
-	e = Ptr(type, e1);
-	if (e != EXP_CANT_INTERPRET)
-	    return e;
-    }
-
-    return this;
-}
-
-Expression *CallExp::optimize(int result)
-{   Expression *e = this;
-
-    e1 = e1->optimize(result);
-    if (e1->op == TOKvar && result & WANTinterpret)
-    {
-	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
-	if (fd)
-	{
-	    Expression *eresult = fd->interpret(NULL, arguments);
-	    if (eresult && eresult != EXP_VOID_INTERPRET)
-		e = eresult;
-	    else if (result & WANTinterpret)
-		error("cannot evaluate %s at compile time", toChars());
-	}
-    }
-    return e;
-}
-
-
-Expression *CastExp::optimize(int result)
-{
-    //printf("CastExp::optimize(result = %d) %s\n", result, toChars());
-    //printf("from %s to %s\n", type->toChars(), to->toChars());
-    //printf("from %s\n", type->toChars());
-    //printf("type = %p\n", type);
-    assert(type);
-    enum TOK op1 = e1->op;
-
-    e1 = e1->optimize(result);
-    if (result & WANTinterpret)
-	e1 = fromConstInitializer(e1);
-
-    if ((e1->op == TOKstring || e1->op == TOKarrayliteral) &&
-	(type->ty == Tpointer || type->ty == Tarray) &&
-	type->next->equals(e1->type->next)
-       )
-    {
-	e1->type = type;
-	return e1;
-    }
-    /* The first test here is to prevent infinite loops
-     */
-    if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral)
-	return e1->castTo(NULL, to);
-    if (e1->op == TOKnull &&
-	(type->ty == Tpointer || type->ty == Tclass))
-    {
-	e1->type = type;
-	return e1;
-    }
-
-    if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass)
-    {
-	// See if we can remove an unnecessary cast
-	ClassDeclaration *cdfrom;
-	ClassDeclaration *cdto;
-	int offset;
-
-	cdfrom = e1->type->isClassHandle();
-	cdto   = type->isClassHandle();
-	if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
-	{
-	    e1->type = type;
-	    return e1;
-	}
-    }
-
-    Expression *e;
-
-    if (e1->isConst())
-    {
-	if (e1->op == TOKsymoff)
-	{
-	    if (type->size() == e1->type->size() &&
-		type->toBasetype()->ty != Tsarray)
-	    {
-		e1->type = type;
-		return e1;
-	    }
-	    return this;
-	}
-	if (to->toBasetype()->ty == Tvoid)
-	    e = this;
-	else
-	    e = Cast(type, to, e1);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *BinExp::optimize(int result)
-{
-    //printf("BinExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (op == TOKshlass || op == TOKshrass || op == TOKushrass)
-    {
-	if (e2->isConst() == 1)
-	{
-	    integer_t i2 = e2->toInteger();
-	    d_uns64 sz = e1->type->size() * 8;
-	    if (i2 < 0 || i2 > sz)
-	    {
-        error("shift assign by %lld is outside the range 0..%"PRIuSIZE, i2, sz);
-		e2 = new IntegerExp(0);
-	    }
-	}
-    }
-    return this;
-}
-
-Expression *AddExp::optimize(int result)
-{   Expression *e;
-
-    //printf("AddExp::optimize(%s)\n", toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() && e2->isConst())
-    {
-	if (e1->op == TOKsymoff && e2->op == TOKsymoff)
-	    return this;
-	e = Add(type, e1, e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *MinExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() && e2->isConst())
-    {
-	if (e2->op == TOKsymoff)
-	    return this;
-	e = Min(type, e1, e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *MulExp::optimize(int result)
-{   Expression *e;
-
-    //printf("MulExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-    {
-	e = Mul(type, e1, e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *DivExp::optimize(int result)
-{   Expression *e;
-
-    //printf("DivExp::optimize(%s)\n", toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-    {
-	e = Div(type, e1, e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *ModExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-    {
-	e = Mod(type, e1, e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *))
-{   Expression *ex = e;
-
-    e->e1 = e->e1->optimize(result);
-    e->e2 = e->e2->optimize(result);
-    if (e->e2->isConst() == 1)
-    {
-	integer_t i2 = e->e2->toInteger();
-	d_uns64 sz = e->e1->type->size() * 8;
-	if (i2 < 0 || i2 > sz)
-	{
-        error("shift by %lld is outside the range 0..%"PRIuSIZE, i2, sz);
-	    e->e2 = new IntegerExp(0);
-	}
-	if (e->e1->isConst() == 1)
-	    ex = (*shift)(e->type, e->e1, e->e2);
-    }
-    return ex;
-}
-
-Expression *ShlExp::optimize(int result)
-{
-    //printf("ShlExp::optimize(result = %d) %s\n", result, toChars());
-    return shift_optimize(result, this, Shl);
-}
-
-Expression *ShrExp::optimize(int result)
-{
-    //printf("ShrExp::optimize(result = %d) %s\n", result, toChars());
-    return shift_optimize(result, this, Shr);
-}
-
-Expression *UshrExp::optimize(int result)
-{
-    //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
-    return shift_optimize(result, this, Ushr);
-}
-
-Expression *AndExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-	e = And(type, e1, e2);
-    else
-	e = this;
-    return e;
-}
-
-Expression *OrExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-	e = Or(type, e1, e2);
-    else
-	e = this;
-    return e;
-}
-
-Expression *XorExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-	e = Xor(type, e1, e2);
-    else
-	e = this;
-    return e;
-}
-
-Expression *CommaExp::optimize(int result)
-{   Expression *e;
-
-    //printf("CommaExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(result & WANTinterpret);
-    e2 = e2->optimize(result);
-    if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2))
-    {
-	e = e2;
-	if (e)
-	    e->type = type;
-    }
-    else
-	e = this;
-    //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars());
-    return e;
-}
-
-Expression *ArrayLengthExp::optimize(int result)
-{   Expression *e;
-
-    //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
-    e = this;
-    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
-    {
-	e = ArrayLength(type, e1);
-    }
-    return e;
-}
-
-Expression *EqualExp::optimize(int result)
-{   Expression *e;
-
-    //printf("EqualExp::optimize(result = %x) %s\n", result, toChars());
-    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
-    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
-    e = this;
-
-    Expression *e1 = fromConstInitializer(this->e1);
-    Expression *e2 = fromConstInitializer(this->e2);
-
-    e = Equal(op, type, e1, e2);
-    if (e == EXP_CANT_INTERPRET)
-	e = this;
-    return e;
-}
-
-Expression *IdentityExp::optimize(int result)
-{   Expression *e;
-
-    //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars());
-    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
-    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
-    e = this;
-
-    if (this->e1->isConst() && this->e2->isConst())
-    {
-	e = Identity(op, type, this->e1, this->e2);
-    }
-    return e;
-}
-
-Expression *IndexExp::optimize(int result)
-{   Expression *e;
-
-    //printf("IndexExp::optimize(result = %d) %s\n", result, toChars());
-    Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret));
-    if (result & WANTinterpret)
-	e1 = fromConstInitializer(e1);
-    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
-    e = Index(type, e1, e2);
-    if (e == EXP_CANT_INTERPRET)
-	e = this;
-    return e;
-}
-
-Expression *SliceExp::optimize(int result)
-{   Expression *e;
-
-    //printf("SliceExp::optimize(result = %d) %s\n", result, toChars());
-    e = this;
-    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
-    if (!lwr)
-    {	if (e1->op == TOKstring)
-	{   // Convert slice of string literal into dynamic array
-	    Type *t = e1->type->toBasetype();
-	    if (t->next)
-		e = e1->castTo(NULL, t->next->arrayOf());
-	}
-	return e;
-    }
-    if (result & WANTinterpret)
-	e1 = fromConstInitializer(e1);
-    lwr = lwr->optimize(WANTvalue | (result & WANTinterpret));
-    upr = upr->optimize(WANTvalue | (result & WANTinterpret));
-    e = Slice(type, e1, lwr, upr);
-    if (e == EXP_CANT_INTERPRET)
-	e = this;
-    return e;
-}
-
-Expression *AndAndExp::optimize(int result)
-{   Expression *e;
-
-    //printf("AndAndExp::optimize(%d) %s\n", result, toChars());
-    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
-    e = this;
-    if (e1->isBool(FALSE))
-    {
-	e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type));
-	e->type = type;
-	e = e->optimize(result);
-    }
-    else
-    {
-	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
-	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
-	    error("void has no value");
-	if (e1->isConst())
-	{
-	    if (e2->isConst())
-	    {	int n1 = e1->isBool(1);
-		int n2 = e2->isBool(1);
-
-		e = new IntegerExp(loc, n1 && n2, type);
-	    }
-	    else if (e1->isBool(TRUE))
-		e = new BoolExp(loc, e2, type);
-	}
-    }
-    return e;
-}
-
-Expression *OrOrExp::optimize(int result)
-{   Expression *e;
-
-    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
-    e = this;
-    if (e1->isBool(TRUE))
-    {	// Replace with (e1, 1)
-	e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type));
-	e->type = type;
-	e = e->optimize(result);
-    }
-    else
-    {
-	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
-	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
-	    error("void has no value");
-	if (e1->isConst())
-	{
-	    if (e2->isConst())
-	    {	int n1 = e1->isBool(1);
-		int n2 = e2->isBool(1);
-
-		e = new IntegerExp(loc, n1 || n2, type);
-	    }
-	    else if (e1->isBool(FALSE))
-		e = new BoolExp(loc, e2, type);
-	}
-    }
-    return e;
-}
-
-Expression *CmpExp::optimize(int result)
-{   Expression *e;
-
-    //printf("CmpExp::optimize() %s\n", toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    if (e1->isConst() == 1 && e2->isConst() == 1)
-    {
-	e = Cmp(op, type, this->e1, this->e2);
-    }
-    else
-	e = this;
-    return e;
-}
-
-Expression *CatExp::optimize(int result)
-{   Expression *e;
-
-    //printf("CatExp::optimize(%d) %s\n", result, toChars());
-    e1 = e1->optimize(result);
-    e2 = e2->optimize(result);
-    e = Cat(type, e1, e2);
-    if (e == EXP_CANT_INTERPRET)
-	e = this;
-    return e;
-}
-
-
-Expression *CondExp::optimize(int result)
-{   Expression *e;
-
-    econd = econd->optimize(WANTflags | (result & WANTinterpret));
-    if (econd->isBool(TRUE))
-	e = e1->optimize(result);
-    else if (econd->isBool(FALSE))
-	e = e2->optimize(result);
-    else
-    {	e1 = e1->optimize(result);
-	e2 = e2->optimize(result);
-	e = this;
-    }
-    return e;
-}
-
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "lexer.h"
+#include "mtype.h"
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "init.h"
+
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+
+/*************************************
+ * If expression is a variable with a const initializer,
+ * return that initializer.
+ */
+
+Expression *fromConstInitializer(Expression *e1)
+{
+    //printf("fromConstInitializer(%s)\n", e1->toChars());
+    if (e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v && v->isConst() && v->init)
+	{   Expression *ei = v->init->toExpression();
+	    if (ei && ei->type)
+		e1 = ei;
+	}
+    }
+    return e1;
+}
+
+
+Expression *Expression::optimize(int result)
+{
+    //printf("Expression::optimize(result = x%x) %s\n", result, toChars());
+    return this;
+}
+
+Expression *VarExp::optimize(int result)
+{
+    if (result & WANTinterpret)
+    {
+	return fromConstInitializer(this);
+    }
+    return this;
+}
+
+Expression *TupleExp::optimize(int result)
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	exps->data[i] = (void *)e;
+    }
+    return this;
+}
+
+Expression *ArrayLiteralExp::optimize(int result)
+{
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+
+	    e = e->optimize(WANTvalue | (result & WANTinterpret));
+	    elements->data[i] = (void *)e;
+	}
+    }
+    return this;
+}
+
+Expression *AssocArrayLiteralExp::optimize(int result)
+{
+    assert(keys->dim == values->dim);
+    for (size_t i = 0; i < keys->dim; i++)
+    {   Expression *e = (Expression *)keys->data[i];
+
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	keys->data[i] = (void *)e;
+
+	e = (Expression *)values->data[i];
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	values->data[i] = (void *)e;
+    }
+    return this;
+}
+
+Expression *StructLiteralExp::optimize(int result)
+{
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    if (!e)
+		continue;
+	    e = e->optimize(WANTvalue | (result & WANTinterpret));
+	    elements->data[i] = (void *)e;
+	}
+    }
+    return this;
+}
+
+Expression *TypeExp::optimize(int result)
+{
+    return this;
+}
+
+Expression *UnaExp::optimize(int result)
+{
+    e1 = e1->optimize(result);
+    return this;
+}
+
+Expression *NegExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Neg(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *ComExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Com(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *NotExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Not(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *BoolExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Bool(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *AddrExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AddrExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    // Convert &*ex to ex
+    if (e1->op == TOKstar)
+    {	Expression *ex;
+
+	ex = ((PtrExp *)e1)->e1;
+	if (type->equals(ex->type))
+	    e = ex;
+	else
+	{
+	    e = ex->copy();
+	    e->type = type;
+	}
+	return e;
+    }
+#if !IN_LLVM
+    if (e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	if (!ve->var->isOut() && !ve->var->isRef() &&
+	    !ve->var->isImportedSymbol())
+	{
+	    e = new SymOffExp(loc, ve->var, 0);
+	    e->type = type;
+	    return e;
+	}
+    }
+    if (e1->op == TOKindex)
+    {	// Convert &array[n] to &array+n
+	IndexExp *ae = (IndexExp *)e1;
+
+	if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
+	{
+	    integer_t index = ae->e2->toInteger();
+	    VarExp *ve = (VarExp *)ae->e1;
+	    if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit
+		&& !ve->var->isImportedSymbol())
+	    {
+		TypeSArray *ts = (TypeSArray *)ve->type;
+		integer_t dim = ts->dim->toInteger();
+		if (index < 0 || index >= dim)
+		    error("array index %lld is out of bounds [0..%lld]", index, dim);
+		e = new SymOffExp(loc, ve->var, index * ts->next->size());
+		e->type = type;
+		return e;
+	    }
+	}
+    }
+#endif
+    return this;
+}
+
+Expression *PtrExp::optimize(int result)
+{
+    //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    // Convert *&ex to ex
+    if (e1->op == TOKaddress)
+    {	Expression *e;
+	Expression *ex;
+
+	ex = ((AddrExp *)e1)->e1;
+	if (type->equals(ex->type))
+	    e = ex;
+	else
+	{
+	    e = ex->copy();
+	    e->type = type;
+	}
+	return e;
+    }
+    // Constant fold *(&structliteral + offset)
+    if (e1->op == TOKadd)
+    {
+	Expression *e;
+	e = Ptr(type, e1);
+	if (e != EXP_CANT_INTERPRET)
+	    return e;
+    }
+
+    return this;
+}
+
+Expression *CallExp::optimize(int result)
+{   Expression *e = this;
+
+    e1 = e1->optimize(result);
+    if (e1->op == TOKvar && result & WANTinterpret)
+    {
+	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
+	if (fd)
+	{
+	    Expression *eresult = fd->interpret(NULL, arguments);
+	    if (eresult && eresult != EXP_VOID_INTERPRET)
+		e = eresult;
+	    else if (result & WANTinterpret)
+		error("cannot evaluate %s at compile time", toChars());
+	}
+    }
+    return e;
+}
+
+
+Expression *CastExp::optimize(int result)
+{
+    //printf("CastExp::optimize(result = %d) %s\n", result, toChars());
+    //printf("from %s to %s\n", type->toChars(), to->toChars());
+    //printf("from %s\n", type->toChars());
+    //printf("type = %p\n", type);
+    assert(type);
+    enum TOK op1 = e1->op;
+
+    e1 = e1->optimize(result);
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+
+    if ((e1->op == TOKstring || e1->op == TOKarrayliteral) &&
+	(type->ty == Tpointer || type->ty == Tarray) &&
+	type->next->equals(e1->type->next)
+       )
+    {
+	e1->type = type;
+	return e1;
+    }
+    /* The first test here is to prevent infinite loops
+     */
+    if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral)
+	return e1->castTo(NULL, to);
+    if (e1->op == TOKnull &&
+	(type->ty == Tpointer || type->ty == Tclass))
+    {
+	e1->type = type;
+	return e1;
+    }
+
+    if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass)
+    {
+	// See if we can remove an unnecessary cast
+	ClassDeclaration *cdfrom;
+	ClassDeclaration *cdto;
+	int offset;
+
+	cdfrom = e1->type->isClassHandle();
+	cdto   = type->isClassHandle();
+	if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
+	{
+	    e1->type = type;
+	    return e1;
+	}
+    }
+
+    Expression *e;
+
+    if (e1->isConst())
+    {
+	if (e1->op == TOKsymoff)
+	{
+	    if (type->size() == e1->type->size() &&
+		type->toBasetype()->ty != Tsarray)
+	    {
+		e1->type = type;
+		return e1;
+	    }
+	    return this;
+	}
+	if (to->toBasetype()->ty == Tvoid)
+	    e = this;
+	else
+	    e = Cast(type, to, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *BinExp::optimize(int result)
+{
+    //printf("BinExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (op == TOKshlass || op == TOKshrass || op == TOKushrass)
+    {
+	if (e2->isConst() == 1)
+	{
+	    integer_t i2 = e2->toInteger();
+	    d_uns64 sz = e1->type->size() * 8;
+	    if (i2 < 0 || i2 > sz)
+	    {
+        error("shift assign by %lld is outside the range 0..%"PRIuSIZE, i2, sz);
+		e2 = new IntegerExp(0);
+	    }
+	}
+    }
+    return this;
+}
+
+Expression *AddExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AddExp::optimize(%s)\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() && e2->isConst())
+    {
+	if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+	    return this;
+	e = Add(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *MinExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() && e2->isConst())
+    {
+	if (e2->op == TOKsymoff)
+	    return this;
+	e = Min(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *MulExp::optimize(int result)
+{   Expression *e;
+
+    //printf("MulExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Mul(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *DivExp::optimize(int result)
+{   Expression *e;
+
+    //printf("DivExp::optimize(%s)\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Div(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *ModExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Mod(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *))
+{   Expression *ex = e;
+
+    e->e1 = e->e1->optimize(result);
+    e->e2 = e->e2->optimize(result);
+    if (e->e2->isConst() == 1)
+    {
+	integer_t i2 = e->e2->toInteger();
+	d_uns64 sz = e->e1->type->size() * 8;
+	if (i2 < 0 || i2 > sz)
+	{
+        error("shift by %lld is outside the range 0..%"PRIuSIZE, i2, sz);
+	    e->e2 = new IntegerExp(0);
+	}
+	if (e->e1->isConst() == 1)
+	    ex = (*shift)(e->type, e->e1, e->e2);
+    }
+    return ex;
+}
+
+Expression *ShlExp::optimize(int result)
+{
+    //printf("ShlExp::optimize(result = %d) %s\n", result, toChars());
+    return shift_optimize(result, this, Shl);
+}
+
+Expression *ShrExp::optimize(int result)
+{
+    //printf("ShrExp::optimize(result = %d) %s\n", result, toChars());
+    return shift_optimize(result, this, Shr);
+}
+
+Expression *UshrExp::optimize(int result)
+{
+    //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+    return shift_optimize(result, this, Ushr);
+}
+
+Expression *AndExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = And(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *OrExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = Or(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *XorExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = Xor(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *CommaExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CommaExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result & WANTinterpret);
+    e2 = e2->optimize(result);
+    if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2))
+    {
+	e = e2;
+	if (e)
+	    e->type = type;
+    }
+    else
+	e = this;
+    //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars());
+    return e;
+}
+
+Expression *ArrayLengthExp::optimize(int result)
+{   Expression *e;
+
+    //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
+    {
+	e = ArrayLength(type, e1);
+    }
+    return e;
+}
+
+Expression *EqualExp::optimize(int result)
+{   Expression *e;
+
+    //printf("EqualExp::optimize(result = %x) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+
+    Expression *e1 = fromConstInitializer(this->e1);
+    Expression *e2 = fromConstInitializer(this->e2);
+
+    e = Equal(op, type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *IdentityExp::optimize(int result)
+{   Expression *e;
+
+    //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+
+    if (this->e1->isConst() && this->e2->isConst())
+    {
+	e = Identity(op, type, this->e1, this->e2);
+    }
+    return e;
+}
+
+Expression *IndexExp::optimize(int result)
+{   Expression *e;
+
+    //printf("IndexExp::optimize(result = %d) %s\n", result, toChars());
+    Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret));
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = Index(type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *SliceExp::optimize(int result)
+{   Expression *e;
+
+    //printf("SliceExp::optimize(result = %d) %s\n", result, toChars());
+    e = this;
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    if (!lwr)
+    {	if (e1->op == TOKstring)
+	{   // Convert slice of string literal into dynamic array
+	    Type *t = e1->type->toBasetype();
+	    if (t->next)
+		e = e1->castTo(NULL, t->next->arrayOf());
+	}
+	return e;
+    }
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+    lwr = lwr->optimize(WANTvalue | (result & WANTinterpret));
+    upr = upr->optimize(WANTvalue | (result & WANTinterpret));
+    e = Slice(type, e1, lwr, upr);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *AndAndExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AndAndExp::optimize(%d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
+    e = this;
+    if (e1->isBool(FALSE))
+    {
+	e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type));
+	e->type = type;
+	e = e->optimize(result);
+    }
+    else
+    {
+	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
+	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
+	    error("void has no value");
+	if (e1->isConst())
+	{
+	    if (e2->isConst())
+	    {	int n1 = e1->isBool(1);
+		int n2 = e2->isBool(1);
+
+		e = new IntegerExp(loc, n1 && n2, type);
+	    }
+	    else if (e1->isBool(TRUE))
+		e = new BoolExp(loc, e2, type);
+	}
+    }
+    return e;
+}
+
+Expression *OrOrExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
+    e = this;
+    if (e1->isBool(TRUE))
+    {	// Replace with (e1, 1)
+	e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type));
+	e->type = type;
+	e = e->optimize(result);
+    }
+    else
+    {
+	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
+	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
+	    error("void has no value");
+	if (e1->isConst())
+	{
+	    if (e2->isConst())
+	    {	int n1 = e1->isBool(1);
+		int n2 = e2->isBool(1);
+
+		e = new IntegerExp(loc, n1 || n2, type);
+	    }
+	    else if (e1->isBool(FALSE))
+		e = new BoolExp(loc, e2, type);
+	}
+    }
+    return e;
+}
+
+Expression *CmpExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CmpExp::optimize() %s\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Cmp(op, type, this->e1, this->e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *CatExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CatExp::optimize(%d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    e = Cat(type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+
+Expression *CondExp::optimize(int result)
+{   Expression *e;
+
+    econd = econd->optimize(WANTflags | (result & WANTinterpret));
+    if (econd->isBool(TRUE))
+	e = e1->optimize(result);
+    else if (econd->isBool(FALSE))
+	e = e2->optimize(result);
+    else
+    {	e1 = e1->optimize(result);
+	e2 = e2->optimize(result);
+	e = this;
+    }
+    return e;
+}
+
+
--- a/dmd/parse.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/parse.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,4919 +1,5156 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "mem.h"
-#include "lexer.h"
-#include "parse.h"
-#include "init.h"
-#include "attrib.h"
-#include "cond.h"
-#include "mtype.h"
-#include "template.h"
-#include "staticassert.h"
-#include "expression.h"
-#include "statement.h"
-#include "module.h"
-#include "dsymbol.h"
-#include "import.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "enum.h"
-#include "id.h"
-#include "version.h"
-
-// How multiple declarations are parsed.
-// If 1, treat as C.
-// If 0, treat:
-//	int *p, i;
-// as:
-//	int* p;
-//	int* i;
-#define CDECLSYNTAX	0
-
-// Support C cast syntax:
-//	(type)(expression)
-#define CCASTSYNTAX	1
-
-// Support C array declarations, such as
-//	int a[3][4];
-#define CARRAYDECL	1
-
-// Support left-to-right array declarations
-#define LTORARRAYDECL	1
-
-
-Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
-    : Lexer(module, base, 0, length, doDocComment, 0)
-{
-    //printf("Parser::Parser()\n");
-    md = NULL;
-    linkage = LINKd;
-    endloc = 0;
-    inBrackets = 0;
-    //nextToken();		// start up the scanner
-}
-
-Array *Parser::parseModule()
-{
-    Array *decldefs;
-
-    // ModuleDeclation leads off
-    if (token.value == TOKmodule)
-    {
-	unsigned char *comment = token.blockComment;
-
-	nextToken();
-	if (token.value != TOKidentifier)
-	{   error("Identifier expected following module");
-	    goto Lerr;
-	}
-	else
-	{
-	    Array *a = NULL;
-	    Identifier *id;
-
-	    id = token.ident;
-	    while (nextToken() == TOKdot)
-	    {
-		if (!a)
-		    a = new Array();
-		a->push(id);
-		nextToken();
-		if (token.value != TOKidentifier)
-		{   error("Identifier expected following package");
-		    goto Lerr;
-		}
-		id = token.ident;
-	    }
-
-	    md = new ModuleDeclaration(a, id);
-
-	    if (token.value != TOKsemicolon)
-		error("';' expected following module declaration instead of %s", token.toChars());
-	    nextToken();
-	    addComment(mod, comment);
-	}
-    }
-
-    decldefs = parseDeclDefs(0);
-    if (token.value != TOKeof)
-    {	error("unrecognized declaration");
-	goto Lerr;
-    }
-    return decldefs;
-
-Lerr:
-    while (token.value != TOKsemicolon && token.value != TOKeof)
-	nextToken();
-    nextToken();
-    return new Array();
-}
-
-Array *Parser::parseDeclDefs(int once)
-{   Dsymbol *s;
-    Array *decldefs;
-    Array *a;
-    Array *aelse;
-    enum PROT prot;
-    unsigned stc;
-    Condition *condition;
-    unsigned char *comment;
-
-    //printf("Parser::parseDeclDefs()\n");
-    decldefs = new Array();
-    do
-    {
-	comment = token.blockComment;
-	switch (token.value)
-	{
-	    case TOKenum:
-		s = parseEnum();
-		break;
-
-	    case TOKstruct:
-	    case TOKunion:
-	    case TOKclass:
-	    case TOKinterface:
-		s = parseAggregate();
-		break;
-
-	    case TOKimport:
-		s = parseImport(decldefs, 0);
-		break;
-
-	    case TOKtemplate:
-		s = (Dsymbol *)parseTemplateDeclaration();
-		break;
-
-	    case TOKmixin:
-	    {	Loc loc = this->loc;
-		if (peek(&token)->value == TOKlparen)
-		{   // mixin(string)
-		    nextToken();
-		    check(TOKlparen, "mixin");
-		    Expression *e = parseAssignExp();
-		    check(TOKrparen);
-		    check(TOKsemicolon);
-		    s = new CompileDeclaration(loc, e);
-		    break;
-		}
-		s = parseMixin();
-		break;
-	    }
-
-	    CASE_BASIC_TYPES:
-	    case TOKalias:
-	    case TOKtypedef:
-	    case TOKidentifier:
-	    case TOKtypeof:
-	    case TOKdot:
-	    Ldeclaration:
-		a = parseDeclarations();
-		decldefs->append(a);
-		continue;
-
-	    case TOKthis:
-		s = parseCtor();
-		break;
-
-	    case TOKtilde:
-		s = parseDtor();
-		break;
-
-	    case TOKinvariant:
-#if 1
-		s = parseInvariant();
-#else
-		if (peek(&token)->value == TOKlcurly)
-		    s = parseInvariant();
-		else
-		{
-		    stc = STCinvariant;
-		    goto Lstc;
-		}
-#endif
-		break;
-
-	    case TOKunittest:
-		s = parseUnitTest();
-		break;
-
-	    case TOKnew:
-		s = parseNew();
-		break;
-
-	    case TOKdelete:
-		s = parseDelete();
-		break;
-
-	    case TOKeof:
-	    case TOKrcurly:
-		return decldefs;
-
-	    case TOKstatic:
-		nextToken();
-		if (token.value == TOKthis)
-		    s = parseStaticCtor();
-		else if (token.value == TOKtilde)
-		    s = parseStaticDtor();
-		else if (token.value == TOKassert)
-		    s = parseStaticAssert();
-		else if (token.value == TOKif)
-		{   condition = parseStaticIfCondition();
-		    a = parseBlock();
-		    aelse = NULL;
-		    if (token.value == TOKelse)
-		    {   nextToken();
-			aelse = parseBlock();
-		    }
-		    s = new StaticIfDeclaration(condition, a, aelse);
-		    break;
-		}
-		else if (token.value == TOKimport)
-		{
-		    s = parseImport(decldefs, 1);
-		}
-		else
-		{   stc = STCstatic;
-		    goto Lstc2;
-		}
-		break;
-
-	    case TOKconst:	  stc = STCconst;	 goto Lstc;
-	    case TOKfinal:	  stc = STCfinal;	 goto Lstc;
-	    case TOKauto:	  stc = STCauto;	 goto Lstc;
-	    case TOKscope:	  stc = STCscope;	 goto Lstc;
-	    case TOKoverride:	  stc = STCoverride;	 goto Lstc;
-	    case TOKabstract:	  stc = STCabstract;	 goto Lstc;
-	    case TOKsynchronized: stc = STCsynchronized; goto Lstc;
-	    case TOKdeprecated:   stc = STCdeprecated;	 goto Lstc;
-
-	    Lstc:
-		nextToken();
-	    Lstc2:
-		switch (token.value)
-		{
-		    case TOKconst:	  stc |= STCconst;	 goto Lstc;
-		    case TOKfinal:	  stc |= STCfinal;	 goto Lstc;
-		    case TOKauto:	  stc |= STCauto;	 goto Lstc;
-		    case TOKscope:	  stc |= STCscope;	 goto Lstc;
-		    case TOKoverride:	  stc |= STCoverride;	 goto Lstc;
-		    case TOKabstract:	  stc |= STCabstract;	 goto Lstc;
-		    case TOKsynchronized: stc |= STCsynchronized; goto Lstc;
-		    case TOKdeprecated:   stc |= STCdeprecated;	 goto Lstc;
-		    //case TOKinvariant:    stc |= STCinvariant;   goto Lstc;
-		    default:
-			break;
-		}
-
-		/* Look for auto initializers:
-		 *	storage_class identifier = initializer;
-		 */
-		if (token.value == TOKidentifier &&
-		    peek(&token)->value == TOKassign)
-		{
-		    while (1)
-		    {
-			Identifier *ident = token.ident;
-			nextToken();
-			nextToken();
-			Initializer *init = parseInitializer();
-			VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
-			v->storage_class = stc;
-			s = v;
-			if (token.value == TOKsemicolon)
-			{
-			    nextToken();
-			}
-			else if (token.value == TOKcomma)
-			{
-			    nextToken();
-			    if (token.value == TOKidentifier &&
-				peek(&token)->value == TOKassign)
-			    {
-				decldefs->push(s);
-				addComment(s, comment);
-				continue;
-			    }
-			    else
-				error("Identifier expected following comma");
-			}
-			else
-			    error("semicolon expected following auto declaration, not '%s'", token.toChars());
-			break;
-		    }
-		}
-		else
-		{   a = parseBlock();
-		    s = new StorageClassDeclaration(stc, a);
-		}
-		break;
-
-	    case TOKextern:
-		if (peek(&token)->value != TOKlparen)
-		{   stc = STCextern;
-		    goto Lstc;
-		}
-	    {
-		enum LINK linksave = linkage;
-		linkage = parseLinkage();
-		a = parseBlock();
-		s = new LinkDeclaration(linkage, a);
-		linkage = linksave;
-		break;
-	    }
-	    case TOKprivate:	prot = PROTprivate;	goto Lprot;
-	    case TOKpackage:	prot = PROTpackage;	goto Lprot;
-	    case TOKprotected:	prot = PROTprotected;	goto Lprot;
-	    case TOKpublic:	prot = PROTpublic;	goto Lprot;
-	    case TOKexport:	prot = PROTexport;	goto Lprot;
-
-	    Lprot:
-		nextToken();
-		a = parseBlock();
-		s = new ProtDeclaration(prot, a);
-		break;
-
-	    case TOKalign:
-	    {	unsigned n;
-
-		s = NULL;
-		nextToken();
-		if (token.value == TOKlparen)
-		{
-		    nextToken();
-		    if (token.value == TOKint32v)
-			n = (unsigned)token.uns64value;
-		    else
-		    {	error("integer expected, not %s", token.toChars());
-			n = 1;
-		    }
-		    nextToken();
-		    check(TOKrparen);
-		}
-		else
-		    n = global.structalign;		// default
-
-		a = parseBlock();
-		s = new AlignDeclaration(n, a);
-		break;
-	    }
-
-	    case TOKpragma:
-	    {	Identifier *ident;
-		Expressions *args = NULL;
-
-		nextToken();
-		check(TOKlparen);
-		if (token.value != TOKidentifier)
-		{   error("pragma(identifier expected");
-		    goto Lerror;
-		}
-		ident = token.ident;
-		nextToken();
-		if (token.value == TOKcomma)
-		    args = parseArguments();	// pragma(identifier, args...)
-		else
-		    check(TOKrparen);		// pragma(identifier)
-
-		if (token.value == TOKsemicolon)
-		    a = NULL;
-		else
-		    a = parseBlock();
-		s = new PragmaDeclaration(loc, ident, args, a);
-		break;
-	    }
-
-	    case TOKdebug:
-		nextToken();
-		if (token.value == TOKassign)
-		{
-		    nextToken();
-		    if (token.value == TOKidentifier)
-			s = new DebugSymbol(loc, token.ident);
-		    else if (token.value == TOKint32v)
-			s = new DebugSymbol(loc, (unsigned)token.uns64value);
-		    else
-		    {	error("identifier or integer expected, not %s", token.toChars());
-			s = NULL;
-		    }
-		    nextToken();
-		    if (token.value != TOKsemicolon)
-			error("semicolon expected");
-		    nextToken();
-		    break;
-		}
-
-		condition = parseDebugCondition();
-		goto Lcondition;
-
-	    case TOKversion:
-		nextToken();
-		if (token.value == TOKassign)
-		{
-		    nextToken();
-		    if (token.value == TOKidentifier)
-			s = new VersionSymbol(loc, token.ident);
-		    else if (token.value == TOKint32v)
-			s = new VersionSymbol(loc, (unsigned)token.uns64value);
-		    else
-		    {	error("identifier or integer expected, not %s", token.toChars());
-			s = NULL;
-		    }
-		    nextToken();
-		    if (token.value != TOKsemicolon)
-			error("semicolon expected");
-		    nextToken();
-		    break;
-		}
-		condition = parseVersionCondition();
-		goto Lcondition;
-
-	    Lcondition:
-		a = parseBlock();
-		aelse = NULL;
-		if (token.value == TOKelse)
-		{   nextToken();
-		    aelse = parseBlock();
-		}
-		s = new ConditionalDeclaration(condition, a, aelse);
-		break;
-
-	    case TOKsemicolon:		// empty declaration
-		nextToken();
-		continue;
-
-	    default:
-		error("Declaration expected, not '%s'",token.toChars());
-	    Lerror:
-		while (token.value != TOKsemicolon && token.value != TOKeof)
-		    nextToken();
-		nextToken();
-		s = NULL;
-		continue;
-	}
-	if (s)
-	{   decldefs->push(s);
-	    addComment(s, comment);
-	}
-    } while (!once);
-    return decldefs;
-}
-
-
-/********************************************
- * Parse declarations after an align, protection, or extern decl.
- */
-
-Array *Parser::parseBlock()
-{
-    Array *a = NULL;
-    Dsymbol *s;
-
-    //printf("parseBlock()\n");
-    switch (token.value)
-    {
-	case TOKsemicolon:
-	    error("declaration expected following attribute, not ';'");
-	    nextToken();
-	    break;
-
-	case TOKlcurly:
-	    nextToken();
-	    a = parseDeclDefs(0);
-	    if (token.value != TOKrcurly)
-	    {   /* { */
-		error("matching '}' expected, not %s", token.toChars());
-	    }
-	    else
-		nextToken();
-	    break;
-
-	case TOKcolon:
-	    nextToken();
-#if 0
-	    a = NULL;
-#else
-	    a = parseDeclDefs(0);	// grab declarations up to closing curly bracket
-#endif
-	    break;
-
-	default:
-	    a = parseDeclDefs(1);
-	    break;
-    }
-    return a;
-}
-
-/**********************************
- * Parse a static assertion.
- */
-
-StaticAssert *Parser::parseStaticAssert()
-{
-    Loc loc = this->loc;
-    Expression *exp;
-    Expression *msg = NULL;
-
-    //printf("parseStaticAssert()\n");
-    nextToken();
-    check(TOKlparen);
-    exp = parseAssignExp();
-    if (token.value == TOKcomma)
-    {	nextToken();
-	msg = parseAssignExp();
-    }
-    check(TOKrparen);
-    check(TOKsemicolon);
-    return new StaticAssert(loc, exp, msg);
-}
-
-
-/***********************************
- * Parse extern (linkage)
- * The parser is on the 'extern' token.
- */
-
-enum LINK Parser::parseLinkage()
-{
-    enum LINK link = LINKdefault;
-    nextToken();
-    assert(token.value == TOKlparen);
-    nextToken();
-    if (token.value == TOKidentifier)
-    {   Identifier *id = token.ident;
-
-	nextToken();
-	if (id == Id::Windows)
-	    link = LINKwindows;
-	else if (id == Id::Pascal)
-	    link = LINKpascal;
-	else if (id == Id::D)
-	    link = LINKd;
-	else if (id == Id::C)
-	{
-	    link = LINKc;
-	    if (token.value == TOKplusplus)
-	    {   link = LINKcpp;
-		nextToken();
-	    }
-	}
-	else if (id == Id::System)
-	{
-#if _WIN32
-	    link = LINKwindows;
-#else
-	    link = LINKc;
-#endif
-	}
-	else
-	{
-	    error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
-	    link = LINKd;
-	}
-    }
-    else
-    {
-	link = LINKd;		// default
-    }
-    check(TOKrparen);
-    return link;
-}
-
-/**************************************
- * Parse a debug conditional
- */
-
-Condition *Parser::parseDebugCondition()
-{
-    Condition *c;
-
-    if (token.value == TOKlparen)
-    {
-	nextToken();
-	unsigned level = 1;
-	Identifier *id = NULL;
-
-	if (token.value == TOKidentifier)
-	    id = token.ident;
-	else if (token.value == TOKint32v)
-	    level = (unsigned)token.uns64value;
-	else
-	    error("identifier or integer expected, not %s", token.toChars());
-	nextToken();
-	check(TOKrparen);
-	c = new DebugCondition(mod, level, id);
-    }
-    else
-	c = new DebugCondition(mod, 1, NULL);
-    return c;
-
-}
-
-/**************************************
- * Parse a version conditional
- */
-
-Condition *Parser::parseVersionCondition()
-{
-    Condition *c;
-    unsigned level = 1;
-    Identifier *id = NULL;
-
-    if (token.value == TOKlparen)
-    {
-	nextToken();
-	if (token.value == TOKidentifier)
-	    id = token.ident;
-	else if (token.value == TOKint32v)
-	    level = (unsigned)token.uns64value;
-#if V2
-	/* Allow:
-	 *    version (unittest)
-	 * even though unittest is a keyword
-	 */
-	else if (token.value == TOKunittest)
-	    id = Lexer::idPool(Token::toChars(TOKunittest));
-#endif
-	else
-	    error("identifier or integer expected, not %s", token.toChars());
-	nextToken();
-	check(TOKrparen);
-
-    }
-    else
-       error("(condition) expected following version");
-    c = new VersionCondition(mod, level, id);
-    return c;
-
-}
-
-/***********************************************
- *	static if (expression)
- *	    body
- *	else
- *	    body
- */
-
-Condition *Parser::parseStaticIfCondition()
-{   Expression *exp;
-    Condition *condition;
-    Array *aif;
-    Array *aelse;
-    Loc loc = this->loc;
-
-    nextToken();
-    if (token.value == TOKlparen)
-    {
-	nextToken();
-	exp = parseAssignExp();
-	check(TOKrparen);
-    }
-    else
-    {   error("(expression) expected following static if");
-	exp = NULL;
-    }
-    condition = new StaticIfCondition(loc, exp);
-    return condition;
-}
-
-
-/*****************************************
- * Parse a constructor definition:
- *	this(arguments) { body }
- * Current token is 'this'.
- */
-
-CtorDeclaration *Parser::parseCtor()
-{
-    CtorDeclaration *f;
-    Arguments *arguments;
-    int varargs;
-    Loc loc = this->loc;
-
-    nextToken();
-    arguments = parseParameters(&varargs);
-    f = new CtorDeclaration(loc, 0, arguments, varargs);
-    parseContracts(f);
-    return f;
-}
-
-/*****************************************
- * Parse a destructor definition:
- *	~this() { body }
- * Current token is '~'.
- */
-
-DtorDeclaration *Parser::parseDtor()
-{
-    DtorDeclaration *f;
-    Loc loc = this->loc;
-
-    nextToken();
-    check(TOKthis);
-    check(TOKlparen);
-    check(TOKrparen);
-
-    f = new DtorDeclaration(loc, 0);
-    parseContracts(f);
-    return f;
-}
-
-/*****************************************
- * Parse a static constructor definition:
- *	static this() { body }
- * Current token is 'this'.
- */
-
-StaticCtorDeclaration *Parser::parseStaticCtor()
-{
-    StaticCtorDeclaration *f;
-    Loc loc = this->loc;
-
-    nextToken();
-    check(TOKlparen);
-    check(TOKrparen);
-
-    f = new StaticCtorDeclaration(loc, 0);
-    parseContracts(f);
-    return f;
-}
-
-/*****************************************
- * Parse a static destructor definition:
- *	static ~this() { body }
- * Current token is '~'.
- */
-
-StaticDtorDeclaration *Parser::parseStaticDtor()
-{
-    StaticDtorDeclaration *f;
-    Loc loc = this->loc;
-
-    nextToken();
-    check(TOKthis);
-    check(TOKlparen);
-    check(TOKrparen);
-
-    f = new StaticDtorDeclaration(loc, 0);
-    parseContracts(f);
-    return f;
-}
-
-/*****************************************
- * Parse an invariant definition:
- *	invariant { body }
- * Current token is 'invariant'.
- */
-
-InvariantDeclaration *Parser::parseInvariant()
-{
-    InvariantDeclaration *f;
-    Loc loc = this->loc;
-
-    nextToken();
-    if (token.value == TOKlparen)	// optional ()
-    {
-	nextToken();
-	check(TOKrparen);
-    }
-
-    f = new InvariantDeclaration(loc, 0);
-    f->fbody = parseStatement(PScurly);
-    return f;
-}
-
-/*****************************************
- * Parse a unittest definition:
- *	unittest { body }
- * Current token is 'unittest'.
- */
-
-UnitTestDeclaration *Parser::parseUnitTest()
-{
-    UnitTestDeclaration *f;
-    Statement *body;
-    Loc loc = this->loc;
-
-    nextToken();
-
-    body = parseStatement(PScurly);
-
-    f = new UnitTestDeclaration(loc, this->loc);
-    f->fbody = body;
-    return f;
-}
-
-/*****************************************
- * Parse a new definition:
- *	new(arguments) { body }
- * Current token is 'new'.
- */
-
-NewDeclaration *Parser::parseNew()
-{
-    NewDeclaration *f;
-    Arguments *arguments;
-    int varargs;
-    Loc loc = this->loc;
-
-    nextToken();
-    arguments = parseParameters(&varargs);
-    f = new NewDeclaration(loc, 0, arguments, varargs);
-    parseContracts(f);
-    return f;
-}
-
-/*****************************************
- * Parse a delete definition:
- *	delete(arguments) { body }
- * Current token is 'delete'.
- */
-
-DeleteDeclaration *Parser::parseDelete()
-{
-    DeleteDeclaration *f;
-    Arguments *arguments;
-    int varargs;
-    Loc loc = this->loc;
-
-    nextToken();
-    arguments = parseParameters(&varargs);
-    if (varargs)
-	error("... not allowed in delete function parameter list");
-    f = new DeleteDeclaration(loc, 0, arguments);
-    parseContracts(f);
-    return f;
-}
-
-/**********************************************
- * Parse parameter list.
- */
-
-Arguments *Parser::parseParameters(int *pvarargs)
-{
-    Arguments *arguments = new Arguments();
-    int varargs = 0;
-    int hasdefault = 0;
-
-    check(TOKlparen);
-    while (1)
-    {   Type *tb;
-	Identifier *ai;
-	Type *at;
-	Argument *a;
-	unsigned storageClass;
-	Expression *ae;
-
-	ai = NULL;
-	storageClass = STCin;		// parameter is "in" by default
-	switch (token.value)
-	{
-	    case TOKrparen:
-		break;
-
-	    case TOKdotdotdot:
-		varargs = 1;
-		nextToken();
-		break;
-
-	    case TOKin:
-		storageClass = STCin;
-		nextToken();
-		goto L1;
-
-	    case TOKout:
-		storageClass = STCout;
-		nextToken();
-		goto L1;
-
-	    case TOKinout:
-	    case TOKref:
-		storageClass = STCref;
-		nextToken();
-		goto L1;
-
-	    case TOKlazy:
-		storageClass = STClazy;
-		nextToken();
-		goto L1;
-
-	    default:
-	    L1:
-		tb = parseBasicType();
-		at = parseDeclarator(tb, &ai);
-		ae = NULL;
-		if (token.value == TOKassign)	// = defaultArg
-		{   nextToken();
-		    ae = parseAssignExp();
-		    hasdefault = 1;
-		}
-		else
-		{   if (hasdefault)
-			error("default argument expected for %s",
-				ai ? ai->toChars() : at->toChars());
-		}
-		if (token.value == TOKdotdotdot)
-		{   /* This is:
-		     *	at ai ...
-		     */
-
-		    if (storageClass & (STCout | STCref))
-			error("variadic argument cannot be out or ref");
-		    varargs = 2;
-		    a = new Argument(storageClass, at, ai, ae);
-		    arguments->push(a);
-		    nextToken();
-		    break;
-		}
-		a = new Argument(storageClass, at, ai, ae);
-		arguments->push(a);
-		if (token.value == TOKcomma)
-		{   nextToken();
-		    continue;
-		}
-		break;
-	}
-	break;
-    }
-    check(TOKrparen);
-    *pvarargs = varargs;
-    return arguments;
-}
-
-
-/*************************************
- */
-
-EnumDeclaration *Parser::parseEnum()
-{   EnumDeclaration *e;
-    Identifier *id;
-    Type *t;
-    Loc loc = this->loc;
-
-    //printf("Parser::parseEnum()\n");
-    nextToken();
-    if (token.value == TOKidentifier)
-    {	id = token.ident;
-	nextToken();
-    }
-    else
-	id = NULL;
-
-    if (token.value == TOKcolon)
-    {
-	nextToken();
-	t = parseBasicType();
-    }
-    else
-	t = NULL;
-
-    e = new EnumDeclaration(loc, id, t);
-    if (token.value == TOKsemicolon && id)
- 	nextToken();
-    else if (token.value == TOKlcurly)
-    {
-	//printf("enum definition\n");
-	e->members = new Array();
-	nextToken();
-	unsigned char *comment = token.blockComment;
-	while (token.value != TOKrcurly)
-	{
-	    if (token.value == TOKidentifier)
-	    {	EnumMember *em;
-		Expression *value;
-		Identifier *ident;
-
-		loc = this->loc;
-		ident = token.ident;
-		value = NULL;
-		nextToken();
-		if (token.value == TOKassign)
-		{
-		    nextToken();
-		    value = parseAssignExp();
-		}
-		em = new EnumMember(loc, ident, value);
-		e->members->push(em);
-		if (token.value == TOKrcurly)
-		    ;
-		else
-		{   addComment(em, comment);
-		    comment = NULL;
-		    check(TOKcomma);
-		}
-		addComment(em, comment);
-		comment = token.blockComment;
-	    }
-	    else
-	    {	error("enum member expected");
-		nextToken();
-	    }
-	}
-	nextToken();
-    }
-    else
-	error("enum declaration is invalid");
-
-    return e;
-}
-
-Dsymbol *Parser::parseAggregate()
-{   AggregateDeclaration *a = NULL;
-    int anon = 0;
-    enum TOK tok;
-    Identifier *id;
-    TemplateParameters *tpl = NULL;
-
-    //printf("Parser::parseAggregate()\n");
-    tok = token.value;
-    nextToken();
-    if (token.value != TOKidentifier)
-    {	id = NULL;
-    }
-    else
-    {	id = token.ident;
-	nextToken();
-
-	if (token.value == TOKlparen)
-	{   // Class template declaration.
-
-	    // Gather template parameter list
-	    tpl = parseTemplateParameterList();
-	}
-    }
-
-    Loc loc = this->loc;
-    switch (tok)
-    {	case TOKclass:
-	case TOKinterface:
-	{
-	    if (!id)
-		error("anonymous classes not allowed");
-
-	    // Collect base class(es)
-	    BaseClasses *baseclasses = NULL;
-	    if (token.value == TOKcolon)
-	    {
-		nextToken();
-		baseclasses = parseBaseClasses();
-
-		if (token.value != TOKlcurly)
-		    error("members expected");
-	    }
-
-	    if (tok == TOKclass)
-		a = new ClassDeclaration(loc, id, baseclasses);
-	    else
-		a = new InterfaceDeclaration(loc, id, baseclasses);
-	    break;
-	}
-
-	case TOKstruct:
-	    if (id)
-		a = new StructDeclaration(loc, id);
-	    else
-		anon = 1;
-	    break;
-
-	case TOKunion:
-	    if (id)
-		a = new UnionDeclaration(loc, id);
-	    else
-		anon = 2;
-	    break;
-
-	default:
-	    assert(0);
-	    break;
-    }
-    if (a && token.value == TOKsemicolon)
-    { 	nextToken();
-    }
-    else if (token.value == TOKlcurly)
-    {
-	//printf("aggregate definition\n");
-	nextToken();
-	Array *decl = parseDeclDefs(0);
-	if (token.value != TOKrcurly)
-	    error("} expected following member declarations in aggregate");
-	nextToken();
-	if (anon)
-	{
-	    /* Anonymous structs/unions are more like attributes.
-	     */
-	    return new AnonDeclaration(loc, anon - 1, decl);
-	}
-	else
-	    a->members = decl;
-    }
-    else
-    {
-	error("{ } expected following aggregate declaration");
-	a = new StructDeclaration(loc, NULL);
-    }
-
-    if (tpl)
-    {	Array *decldefs;
-	TemplateDeclaration *tempdecl;
-
-	// Wrap a template around the aggregate declaration
-	decldefs = new Array();
-	decldefs->push(a);
-	tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
-	return tempdecl;
-    }
-
-    return a;
-}
-
-/*******************************************
- */
-
-BaseClasses *Parser::parseBaseClasses()
-{
-    enum PROT protection = PROTpublic;
-    BaseClasses *baseclasses = new BaseClasses();
-
-    for (; 1; nextToken())
-    {
-	switch (token.value)
-	{
-	    case TOKidentifier:
-		break;
-	    case TOKprivate:
-		protection = PROTprivate;
-		continue;
-	    case TOKpackage:
-		protection = PROTpackage;
-		continue;
-	    case TOKprotected:
-		protection = PROTprotected;
-		continue;
-	    case TOKpublic:
-		protection = PROTpublic;
-		continue;
-	    default:
-		error("base classes expected instead of %s", token.toChars());
-		return NULL;
-	}
-	BaseClass *b = new BaseClass(parseBasicType(), protection);
-	baseclasses->push(b);
-	if (token.value != TOKcomma)
-	    break;
-	protection = PROTpublic;
-    }
-    return baseclasses;
-}
-
-/**************************************
- * Parse a TemplateDeclaration.
- */
-
-TemplateDeclaration *Parser::parseTemplateDeclaration()
-{
-    TemplateDeclaration *tempdecl;
-    Identifier *id;
-    TemplateParameters *tpl;
-    Array *decldefs;
-    Loc loc = this->loc;
-
-    nextToken();
-    if (token.value != TOKidentifier)
-    {   error("TemplateIdentifier expected following template");
-	goto Lerr;
-    }
-    id = token.ident;
-    nextToken();
-    tpl = parseTemplateParameterList();
-    if (!tpl)
-	goto Lerr;
-
-    if (token.value != TOKlcurly)
-    {	error("members of template declaration expected");
-	goto Lerr;
-    }
-    else
-    {
-	nextToken();
-	decldefs = parseDeclDefs(0);
-	if (token.value != TOKrcurly)
-	{   error("template member expected");
-	    goto Lerr;
-	}
-	nextToken();
-    }
-
-    tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
-    return tempdecl;
-
-Lerr:
-    return NULL;
-}
-
-/******************************************
- * Parse template parameter list.
- */
-
-TemplateParameters *Parser::parseTemplateParameterList()
-{
-    TemplateParameters *tpl = new TemplateParameters();
-
-    if (token.value != TOKlparen)
-    {   error("parenthesized TemplateParameterList expected following TemplateIdentifier");
-	goto Lerr;
-    }
-    nextToken();
-
-    // Get array of TemplateParameters
-    if (token.value != TOKrparen)
-    {	int isvariadic = 0;
-
-	while (1)
-	{   TemplateParameter *tp;
-	    Identifier *tp_ident = NULL;
-	    Type *tp_spectype = NULL;
-	    Type *tp_valtype = NULL;
-	    Type *tp_defaulttype = NULL;
-	    Expression *tp_specvalue = NULL;
-	    Expression *tp_defaultvalue = NULL;
-	    Token *t;
-
-	    // Get TemplateParameter
-
-	    // First, look ahead to see if it is a TypeParameter or a ValueParameter
-	    t = peek(&token);
-	    if (token.value == TOKalias)
-	    {	// AliasParameter
-		nextToken();
-		if (token.value != TOKidentifier)
-		{   error("Identifier expected for template parameter");
-		    goto Lerr;
-		}
-		tp_ident = token.ident;
-		nextToken();
-		if (token.value == TOKcolon)	// : Type
-		{
-		    nextToken();
-		    tp_spectype = parseBasicType();
-		    tp_spectype = parseDeclarator(tp_spectype, NULL);
-		}
-		if (token.value == TOKassign)	// = Type
-		{
-		    nextToken();
-		    tp_defaulttype = parseBasicType();
-		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
-		}
-		tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
-	    }
-	    else if (t->value == TOKcolon || t->value == TOKassign ||
-		     t->value == TOKcomma || t->value == TOKrparen)
-	    {	// TypeParameter
-		if (token.value != TOKidentifier)
-		{   error("Identifier expected for template parameter");
-		    goto Lerr;
-		}
-		tp_ident = token.ident;
-		nextToken();
-		if (token.value == TOKcolon)	// : Type
-		{
-		    nextToken();
-		    tp_spectype = parseBasicType();
-		    tp_spectype = parseDeclarator(tp_spectype, NULL);
-		}
-		if (token.value == TOKassign)	// = Type
-		{
-		    nextToken();
-		    tp_defaulttype = parseBasicType();
-		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
-		}
-		tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
-	    }
-	    else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
-	    {	// ident...
-		if (isvariadic)
-		    error("variadic template parameter must be last");
-		isvariadic = 1;
-		tp_ident = token.ident;
-		nextToken();
-		nextToken();
-		tp = new TemplateTupleParameter(loc, tp_ident);
-	    }
-	    else
-	    {	// ValueParameter
-		tp_valtype = parseBasicType();
-		tp_valtype = parseDeclarator(tp_valtype, &tp_ident);
-		if (!tp_ident)
-		{
-		    error("no identifier for template value parameter");
-		    tp_ident = new Identifier("error", TOKidentifier);
-		}
-		if (token.value == TOKcolon)	// : CondExpression
-		{
-		    nextToken();
-		    tp_specvalue = parseCondExp();
-		}
-		if (token.value == TOKassign)	// = CondExpression
-		{
-		    nextToken();
-		    tp_defaultvalue = parseCondExp();
-		}
-		tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
-	    }
-	    tpl->push(tp);
-	    if (token.value != TOKcomma)
-		break;
-	    nextToken();
-	}
-    }
-    check(TOKrparen);
-Lerr:
-    return tpl;
-}
-
-/******************************************
- * Parse template mixin.
- *	mixin Foo;
- *	mixin Foo!(args);
- *	mixin a.b.c!(args).Foo!(args);
- *	mixin Foo!(args) identifier;
- *	mixin typeof(expr).identifier!(args);
- */
-
-Dsymbol *Parser::parseMixin()
-{
-    TemplateMixin *tm;
-    Identifier *id;
-    Type *tqual;
-    Objects *tiargs;
-    Array *idents;
-
-    //printf("parseMixin()\n");
-    nextToken();
-    tqual = NULL;
-    if (token.value == TOKdot)
-    {
-	id = Id::empty;
-    }
-    else
-    {
-	if (token.value == TOKtypeof)
-	{   Expression *exp;
-
-	    nextToken();
-	    check(TOKlparen);
-	    exp = parseExpression();
-	    check(TOKrparen);
-	    tqual = new TypeTypeof(loc, exp);
-	    check(TOKdot);
-	}
-	if (token.value != TOKidentifier)
-	{
-	    error("identifier expected, not %s", token.toChars());
-	    goto Lerr;
-	}
-	id = token.ident;
-	nextToken();
-    }
-
-    idents = new Array();
-    while (1)
-    {
-	tiargs = NULL;
-	if (token.value == TOKnot)
-	{
-	    nextToken();
-	    tiargs = parseTemplateArgumentList();
-	}
-
-	if (token.value != TOKdot)
-	    break;
-
-	if (tiargs)
-	{   TemplateInstance *tempinst = new TemplateInstance(loc, id);
-	    tempinst->tiargs = tiargs;
-	    id = (Identifier *)tempinst;
-	    tiargs = NULL;
-	}
-	idents->push(id);
-
-	nextToken();
-	if (token.value != TOKidentifier)
-	{   error("identifier expected following '.' instead of '%s'", token.toChars());
-	    break;
-	}
-	id = token.ident;
-	nextToken();
-    }
-    idents->push(id);
-
-    if (token.value == TOKidentifier)
-    {
-	id = token.ident;
-	nextToken();
-    }
-    else
-	id = NULL;
-
-    tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
-    if (token.value != TOKsemicolon)
-	error("';' expected after mixin");
-    nextToken();
-
-    return tm;
-
-Lerr:
-    return NULL;
-}
-
-/******************************************
- * Parse template argument list.
- * Input:
- * 	current token is opening '('
- * Output:
- *	current token is one after closing ')'
- */
-
-Objects *Parser::parseTemplateArgumentList()
-{
-    //printf("Parser::parseTemplateArgumentList()\n");
-    Objects *tiargs = new Objects();
-    if (token.value != TOKlparen)
-    {   error("!(TemplateArgumentList) expected following TemplateIdentifier");
-	return tiargs;
-    }
-    nextToken();
-
-    // Get TemplateArgumentList
-    if (token.value != TOKrparen)
-    {
-	while (1)
-	{
-	    // See if it is an Expression or a Type
-	    if (isDeclaration(&token, 0, TOKreserved, NULL))
-	    {	// Type
-		Type *ta;
-
-		// Get TemplateArgument
-		ta = parseBasicType();
-		ta = parseDeclarator(ta, NULL);
-		tiargs->push(ta);
-	    }
-	    else
-	    {	// Expression
-		Expression *ea;
-
-		ea = parseAssignExp();
-		tiargs->push(ea);
-	    }
-	    if (token.value != TOKcomma)
-		break;
-	    nextToken();
-	}
-    }
-    check(TOKrparen, "template argument list");
-    return tiargs;
-}
-
-Import *Parser::parseImport(Array *decldefs, int isstatic)
-{   Import *s;
-    Identifier *id;
-    Identifier *aliasid = NULL;
-    Array *a;
-    Loc loc;
-
-    //printf("Parser::parseImport()\n");
-    do
-    {
-     L1:
-	nextToken();
-	if (token.value != TOKidentifier)
-	{   error("Identifier expected following import");
-	    break;
-	}
-
-	loc = this->loc;
-	a = NULL;
-	id = token.ident;
-	nextToken();
-	if (!aliasid && token.value == TOKassign)
-	{
-	    aliasid = id;
-	    goto L1;
-	}
-	while (token.value == TOKdot)
-	{
-	    if (!a)
-		a = new Array();
-	    a->push(id);
-	    nextToken();
-	    if (token.value != TOKidentifier)
-	    {   error("Identifier expected following package");
-		break;
-	    }
-	    id = token.ident;
-	    nextToken();
-	}
-
-	s = new Import(loc, a, token.ident, aliasid, isstatic);
-	decldefs->push(s);
-
-	/* Look for
-	 *	: alias=name, alias=name;
-	 * syntax.
-	 */
-	if (token.value == TOKcolon)
-	{
-	    do
-	    {	Identifier *name;
-		Identifier *alias;
-
-		nextToken();
-		if (token.value != TOKidentifier)
-		{   error("Identifier expected following :");
-		    break;
-		}
-		alias = token.ident;
-		nextToken();
-		if (token.value == TOKassign)
-		{
-		    nextToken();
-		    if (token.value != TOKidentifier)
-		    {   error("Identifier expected following %s=", alias->toChars());
-			break;
-		    }
-		    name = token.ident;
-		    nextToken();
-		}
-		else
-		{   name = alias;
-		    alias = NULL;
-		}
-		s->addAlias(name, alias);
-	    } while (token.value == TOKcomma);
-	    break;	// no comma-separated imports of this form
-	}
-
-	aliasid = NULL;
-    } while (token.value == TOKcomma);
-
-    if (token.value == TOKsemicolon)
- 	nextToken();
-    else
-    {
-	error("';' expected");
-	nextToken();
-    }
-
-    return NULL;
-}
-
-Type *Parser::parseBasicType()
-{   Type *t;
-    Identifier *id;
-    TypeQualified *tid;
-    TemplateInstance *tempinst;
-
-    //printf("parseBasicType()\n");
-    switch (token.value)
-    {
-	CASE_BASIC_TYPES_X(t):
-	    nextToken();
-	    break;
-
-	case TOKidentifier:
-	    id = token.ident;
-	    nextToken();
-	    if (token.value == TOKnot)
-	    {
-		nextToken();
-		tempinst = new TemplateInstance(loc, id);
-		tempinst->tiargs = parseTemplateArgumentList();
-		tid = new TypeInstance(loc, tempinst);
-		goto Lident2;
-	    }
-	Lident:
-	    tid = new TypeIdentifier(loc, id);
-	Lident2:
-	    while (token.value == TOKdot)
-	    {	nextToken();
-		if (token.value != TOKidentifier)
-		{   error("identifier expected following '.' instead of '%s'", token.toChars());
-		    break;
-		}
-		id = token.ident;
-		nextToken();
-		if (token.value == TOKnot)
-		{
-		    nextToken();
-		    tempinst = new TemplateInstance(loc, id);
-		    tempinst->tiargs = parseTemplateArgumentList();
-		    tid->addIdent((Identifier *)tempinst);
-		}
-		else
-		    tid->addIdent(id);
-	    }
-	    t = tid;
-	    break;
-
-	case TOKdot:
-	    id = Id::empty;
-	    goto Lident;
-
-	case TOKtypeof:
-	{   Expression *exp;
-
-	    nextToken();
-	    check(TOKlparen);
-	    exp = parseExpression();
-	    check(TOKrparen);
-	    tid = new TypeTypeof(loc, exp);
-	    goto Lident2;
-	}
-
-	default:
-	    error("basic type expected, not %s", token.toChars());
-	    t = Type::tint32;
-	    break;
-    }
-    return t;
-}
-
-Type *Parser::parseBasicType2(Type *t)
-{
-    Type *ts;
-    Type *ta;
-
-    //printf("parseBasicType2()\n");
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKmul:
-		t = new TypePointer(t);
-		nextToken();
-		continue;
-
-	    case TOKlbracket:
-#if LTORARRAYDECL
-		// Handle []. Make sure things like
-		//     int[3][1] a;
-		// is (array[1] of array[3] of int)
-		nextToken();
-		if (token.value == TOKrbracket)
-		{
-		    t = new TypeDArray(t);			// []
-		    nextToken();
-		}
-		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
-		{   // It's an associative array declaration
-		    Type *index;
-
-		    //printf("it's an associative array\n");
-		    index = parseBasicType();
-		    index = parseDeclarator(index, NULL);	// [ type ]
-		    t = new TypeAArray(t, index);
-		    check(TOKrbracket);
-		}
-		else
-		{
-		    //printf("it's [expression]\n");
-		    inBrackets++;
-		    Expression *e = parseExpression();		// [ expression ]
-		    if (token.value == TOKslice)
-		    {	Expression *e2;
-
-			nextToken();
-			e2 = parseExpression();			// [ exp .. exp ]
-			t = new TypeSlice(t, e, e2);
-		    }
-		    else
-			t = new TypeSArray(t,e);
-		    inBrackets--;
-		    check(TOKrbracket);
-		}
-		continue;
-#else
-		// Handle []. Make sure things like
-		//     int[3][1] a;
-		// is (array[3] of array[1] of int)
-		ts = t;
-		while (token.value == TOKlbracket)
-		{
-		    nextToken();
-		    if (token.value == TOKrbracket)
-		    {
-			ta = new TypeDArray(t);			// []
-			nextToken();
-		    }
-		    else if (isDeclaration(&token, 0, TOKrbracket, NULL))
-		    {   // It's an associative array declaration
-			Type *index;
-
-			//printf("it's an associative array\n");
-			index = parseBasicType();
-			index = parseDeclarator(index, NULL);	// [ type ]
-			check(TOKrbracket);
-			ta = new TypeAArray(t, index);
-		    }
-		    else
-		    {
-			//printf("it's [expression]\n");
-			Expression *e = parseExpression();	// [ expression ]
-			ta = new TypeSArray(t,e);
-			check(TOKrbracket);
-		    }
-		    Type **pt;
-		    for (pt = &ts; *pt != t; pt = &(*pt)->next)
-			;
-		    *pt = ta;
-		}
-		t = ts;
-		continue;
-#endif
-
-	    case TOKdelegate:
-	    case TOKfunction:
-	    {	// Handle delegate declaration:
-		//	t delegate(parameter list)
-		//	t function(parameter list)
-		Arguments *arguments;
-		int varargs;
-		enum TOK save = token.value;
-
-		nextToken();
-		arguments = parseParameters(&varargs);
-		t = new TypeFunction(arguments, t, varargs, linkage);
-		if (save == TOKdelegate)
-		    t = new TypeDelegate(t);
-		else
-		    t = new TypePointer(t);	// pointer to function
-		continue;
-	    }
-
-	    default:
-		ts = t;
-		break;
-	}
-	break;
-    }
-    return ts;
-}
-
-Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
-{   Type *ts;
-    Type *ta;
-
-    //printf("parseDeclarator(tpl = %p)\n", tpl);
-    t = parseBasicType2(t);
-
-    switch (token.value)
-    {
-
-	case TOKidentifier:
-	    if (pident)
-		*pident = token.ident;
-	    else
-		error("unexpected identifer '%s' in declarator", token.ident->toChars());
-	    ts = t;
-	    nextToken();
-	    break;
-
-	case TOKlparen:
-	    nextToken();
-	    ts = parseDeclarator(t, pident);
-	    check(TOKrparen);
-	    break;
-
-	default:
-	    ts = t;
-	    break;
-    }
-
-    while (1)
-    {
-	switch (token.value)
-	{
-#if CARRAYDECL
-	    case TOKlbracket:
-	    {	// This is the old C-style post [] syntax.
-		nextToken();
-		if (token.value == TOKrbracket)
-		{
-		    ta = new TypeDArray(t);			// []
-		    nextToken();
-		}
-		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
-		{   // It's an associative array declaration
-		    Type *index;
-
-		    //printf("it's an associative array\n");
-		    index = parseBasicType();
-		    index = parseDeclarator(index, NULL);	// [ type ]
-		    check(TOKrbracket);
-		    ta = new TypeAArray(t, index);
-		}
-		else
-		{
-		    //printf("it's [expression]\n");
-		    Expression *e = parseExpression();		// [ expression ]
-		    ta = new TypeSArray(t, e);
-		    check(TOKrbracket);
-		}
-		Type **pt;
-		for (pt = &ts; *pt != t; pt = &(*pt)->next)
-		    ;
-		*pt = ta;
-		continue;
-	    }
-#endif
-	    case TOKlparen:
-	    {	Arguments *arguments;
-		int varargs;
-
-		if (tpl)
-		{
-		    /* Look ahead to see if this is (...)(...),
-		     * i.e. a function template declaration
-		     */
-		    if (peekPastParen(&token)->value == TOKlparen)
-		    {   // It's a function template declaration
-			//printf("function template declaration\n");
-
-			// Gather template parameter list
-			*tpl = parseTemplateParameterList();
-		    }
-		}
-
-		arguments = parseParameters(&varargs);
-		Type *ta = new TypeFunction(arguments, t, varargs, linkage);
-		Type **pt;
-		for (pt = &ts; *pt != t; pt = &(*pt)->next)
-		    ;
-		*pt = ta;
-		break;
-	    }
-	}
-	break;
-    }
-
-    return ts;
-}
-
-/**********************************
- * Return array of Declaration *'s.
- */
-
-Array *Parser::parseDeclarations()
-{
-    enum STC storage_class;
-    enum STC stc;
-    Type *ts;
-    Type *t;
-    Type *tfirst;
-    Identifier *ident;
-    Array *a;
-    enum TOK tok;
-    unsigned char *comment = token.blockComment;
-    enum LINK link = linkage;
-
-    //printf("parseDeclarations()\n");
-    switch (token.value)
-    {
-	case TOKtypedef:
-	case TOKalias:
-	    tok = token.value;
-	    nextToken();
-	    break;
-
-	default:
-	    tok = TOKreserved;
-	    break;
-    }
-
-    storage_class = STCundefined;
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKconst:	stc = STCconst;		 goto L1;
-	    case TOKstatic:	stc = STCstatic;	 goto L1;
-	    case TOKfinal:	stc = STCfinal;		 goto L1;
-	    case TOKauto:	stc = STCauto;		 goto L1;
-	    case TOKscope:	stc = STCscope;		 goto L1;
-	    case TOKoverride:	stc = STCoverride;	 goto L1;
-	    case TOKabstract:	stc = STCabstract;	 goto L1;
-	    case TOKsynchronized: stc = STCsynchronized; goto L1;
-	    case TOKdeprecated: stc = STCdeprecated;	 goto L1;
-	    L1:
-		if (storage_class & stc)
-		    error("redundant storage class '%s'", token.toChars());
-		storage_class = (STC) (storage_class | stc);
-		nextToken();
-		continue;
-
-	    case TOKextern:
-		if (peek(&token)->value != TOKlparen)
-		{   stc = STCextern;
-		    goto L1;
-		}
-
-		link = parseLinkage();
-		continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-
-    a = new Array();
-
-    /* Look for auto initializers:
-     *	storage_class identifier = initializer;
-     */
-    while (storage_class &&
-	token.value == TOKidentifier &&
-	peek(&token)->value == TOKassign)
-    {
-	ident = token.ident;
-	nextToken();
-	nextToken();
-	Initializer *init = parseInitializer();
-	VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
-	v->storage_class = storage_class;
-	a->push(v);
-	if (token.value == TOKsemicolon)
-	{
-	    nextToken();
-	    addComment(v, comment);
-	}
-	else if (token.value == TOKcomma)
-	{
-	    nextToken();
-	    if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
-	    {
-		error("Identifier expected following comma");
-	    }
-	    else
-		continue;
-	}
-	else
-	    error("semicolon expected following auto declaration, not '%s'", token.toChars());
-	return a;
-    }
-
-    if (token.value == TOKclass)
-    {	AggregateDeclaration *s;
-
-	s = (AggregateDeclaration *)parseAggregate();
-	s->storage_class |= storage_class;
-	a->push(s);
-	addComment(s, comment);
-	return a;
-    }
-
-    ts = parseBasicType();
-    ts = parseBasicType2(ts);
-    tfirst = NULL;
-
-    while (1)
-    {
-	Loc loc = this->loc;
-	TemplateParameters *tpl = NULL;
-
-	ident = NULL;
-	t = parseDeclarator(ts, &ident, &tpl);
-	assert(t);
-	if (!tfirst)
-	    tfirst = t;
-	else if (t != tfirst)
-	    error("multiple declarations must have the same type, not %s and %s",
-		tfirst->toChars(), t->toChars());
-	if (!ident)
-	    error("no identifier for declarator %s", t->toChars());
-
-	if (tok == TOKtypedef || tok == TOKalias)
-	{   Declaration *v;
-	    Initializer *init;
-
-	    init = NULL;
-	    if (token.value == TOKassign)
-	    {
-		nextToken();
-		init = parseInitializer();
-	    }
-	    if (tok == TOKtypedef)
-		v = new TypedefDeclaration(loc, ident, t, init);
-	    else
-	    {	if (init)
-		    error("alias cannot have initializer");
-		v = new AliasDeclaration(loc, ident, t);
-	    }
-	    v->storage_class = storage_class;
-	    if (link == linkage)
-		a->push(v);
-	    else
-	    {
-		Array *ax = new Array();
-		ax->push(v);
-		Dsymbol *s = new LinkDeclaration(link, ax);
-		a->push(s);
-	    }
-	    switch (token.value)
-	    {   case TOKsemicolon:
-		    nextToken();
-		    addComment(v, comment);
-		    break;
-
-		case TOKcomma:
-		    nextToken();
-		    addComment(v, comment);
-		    continue;
-
-		default:
-		    error("semicolon expected to close %s declaration", Token::toChars(tok));
-		    break;
-	    }
-	}
-	else if (t->ty == Tfunction)
-	{   FuncDeclaration *f;
-	    Dsymbol *s;
-
-	    f = new FuncDeclaration(loc, 0, ident, storage_class, t);
-	    addComment(f, comment);
-	    parseContracts(f);
-	    addComment(f, NULL);
-	    if (link == linkage)
-	    {
-		s = f;
-	    }
-	    else
-	    {
-		Array *ax = new Array();
-		ax->push(f);
-		s = new LinkDeclaration(link, ax);
-	    }
-	    if (tpl)			// it's a function template
-	    {   Array *decldefs;
-		TemplateDeclaration *tempdecl;
-
-		// Wrap a template around the aggregate declaration
-		decldefs = new Array();
-		decldefs->push(s);
-		tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs);
-		s = tempdecl;
-	    }
-	    addComment(s, comment);
-	    a->push(s);
-	}
-	else
-	{   VarDeclaration *v;
-	    Initializer *init;
-
-	    init = NULL;
-	    if (token.value == TOKassign)
-	    {
-		nextToken();
-		init = parseInitializer();
-	    }
-	    v = new VarDeclaration(loc, t, ident, init);
-	    v->storage_class = storage_class;
-	    if (link == linkage)
-		a->push(v);
-	    else
-	    {
-		Array *ax = new Array();
-		ax->push(v);
-		Dsymbol *s = new LinkDeclaration(link, ax);
-		a->push(s);
-	    }
-	    switch (token.value)
-	    {   case TOKsemicolon:
-		    nextToken();
-		    addComment(v, comment);
-		    break;
-
-		case TOKcomma:
-		    nextToken();
-		    addComment(v, comment);
-		    continue;
-
-		default:
-		    error("semicolon expected, not '%s'", token.toChars());
-		    break;
-	    }
-	}
-	break;
-    }
-    return a;
-}
-
-/*****************************************
- * Parse contracts following function declaration.
- */
-
-void Parser::parseContracts(FuncDeclaration *f)
-{
-    Type *tb;
-    enum LINK linksave = linkage;
-
-    // The following is irrelevant, as it is overridden by sc->linkage in
-    // TypeFunction::semantic
-    linkage = LINKd;		// nested functions have D linkage
-L1:
-    switch (token.value)
-    {
-	case TOKlcurly:
-	    if (f->frequire || f->fensure)
-		error("missing body { ... } after in or out");
-	    f->fbody = parseStatement(PSsemi);
-	    f->endloc = endloc;
-	    break;
-
-	case TOKbody:
-	    nextToken();
-	    f->fbody = parseStatement(PScurly);
-	    f->endloc = endloc;
-	    break;
-
-	case TOKsemicolon:
-	    if (f->frequire || f->fensure)
-		error("missing body { ... } after in or out");
-	    nextToken();
-	    break;
-
-#if 0	// Do we want this for function declarations, so we can do:
-    // int x, y, foo(), z;
-	case TOKcomma:
-	    nextToken();
-	    continue;
-#endif
-
-#if 0 // Dumped feature
-	case TOKthrow:
-	    if (!f->fthrows)
-		f->fthrows = new Array();
-	    nextToken();
-	    check(TOKlparen);
-	    while (1)
-	    {
-		tb = parseBasicType();
-		f->fthrows->push(tb);
-		if (token.value == TOKcomma)
-		{   nextToken();
-		    continue;
-		}
-		break;
-	    }
-	    check(TOKrparen);
-	    goto L1;
-#endif
-
-	case TOKin:
-	    nextToken();
-	    if (f->frequire)
-		error("redundant 'in' statement");
-	    f->frequire = parseStatement(PScurly | PSscope);
-	    goto L1;
-
-	case TOKout:
-	    // parse: out (identifier) { statement }
-	    nextToken();
-	    if (token.value != TOKlcurly)
-	    {
-		check(TOKlparen);
-		if (token.value != TOKidentifier)	   
-		    error("(identifier) following 'out' expected, not %s", token.toChars());
-		f->outId = token.ident;
-		nextToken();
-		check(TOKrparen);
-	    }
-	    if (f->fensure)
-		error("redundant 'out' statement");
-	    f->fensure = parseStatement(PScurly | PSscope);
-	    goto L1;
-
-	default:
-	    error("semicolon expected following function declaration");
-	    break;
-    }
-    linkage = linksave;
-}
-
-/*****************************************
- */
-
-Initializer *Parser::parseInitializer()
-{
-    StructInitializer *is;
-    ArrayInitializer *ia;
-    ExpInitializer *ie;
-    Expression *e;
-    Identifier *id;
-    Initializer *value;
-    int comma;
-    Loc loc = this->loc;
-    Token *t;
-    int braces;
-
-    switch (token.value)
-    {
-	case TOKlcurly:
-	    /* Scan ahead to see if it is a struct initializer or
-	     * a function literal.
-	     * If it contains a ';', it is a function literal.
-	     * Treat { } as a struct initializer.
-	     */
-	    braces = 1;
-	    for (t = peek(&token); 1; t = peek(t))
-	    {
-		switch (t->value)
-		{
-		    case TOKsemicolon:
-		    case TOKreturn:
-			goto Lexpression;
-
-		    case TOKlcurly:
-			braces++;
-			continue;
-
-		    case TOKrcurly:
-			if (--braces == 0)
-			    break;
-			continue;
-
-		    case TOKeof:
-			break;
-
-		    default:
-			continue;
-		}
-		break;
-	    }
-
-	    is = new StructInitializer(loc);
-	    nextToken();
-	    comma = 0;
-	    while (1)
-	    {
-		switch (token.value)
-		{
-		    case TOKidentifier:
-			if (comma == 1)
-			    error("comma expected separating field initializers");
-			t = peek(&token);
-			if (t->value == TOKcolon)
-			{
-			    id = token.ident;
-			    nextToken();
-			    nextToken();	// skip over ':'
-			}
-			else
-			{   id = NULL;
-			}
-			value = parseInitializer();
-			is->addInit(id, value);
-			comma = 1;
-			continue;
-
-		    case TOKcomma:
-			nextToken();
-			comma = 2;
-			continue;
-
-		    case TOKrcurly:		// allow trailing comma's
-			nextToken();
-			break;
-
-		    case TOKeof:
-			error("found EOF instead of initializer");
-			break;
-
-		    default:
-			value = parseInitializer();
-			is->addInit(NULL, value);
-			comma = 1;
-			continue;
-			//error("found '%s' instead of field initializer", token.toChars());
-			//break;
-		}
-		break;
-	    }
-	    return is;
-
-	case TOKlbracket:
-	    ia = new ArrayInitializer(loc);
-	    nextToken();
-	    comma = 0;
-	    while (1)
-	    {
-		switch (token.value)
-		{
-		    default:
-			if (comma == 1)
-			{   error("comma expected separating array initializers, not %s", token.toChars());
-			    nextToken();
-			    break;
-			}
-			e = parseAssignExp();
-			if (!e)
-			    break;
-			if (token.value == TOKcolon)
-			{
-			    nextToken();
-			    value = parseInitializer();
-			}
-			else
-			{   value = new ExpInitializer(e->loc, e);
-			    e = NULL;
-			}
-			ia->addInit(e, value);
-			comma = 1;
-			continue;
-
-		    case TOKlcurly:
-		    case TOKlbracket:
-			if (comma == 1)
-			    error("comma expected separating array initializers, not %s", token.toChars());
-			value = parseInitializer();
-			ia->addInit(NULL, value);
-			comma = 1;
-			continue;
-
-		    case TOKcomma:
-			nextToken();
-			comma = 2;
-			continue;
-
-		    case TOKrbracket:		// allow trailing comma's
-			nextToken();
-			break;
-
-		    case TOKeof:
-			error("found '%s' instead of array initializer", token.toChars());
-			break;
-		}
-		break;
-	    }
-	    return ia;
-
-	case TOKvoid:
-	    t = peek(&token);
-	    if (t->value == TOKsemicolon || t->value == TOKcomma)
-	    {
-		nextToken();
-		return new VoidInitializer(loc);
-	    }
-	    goto Lexpression;
-
-	default:
-	Lexpression:
-	    e = parseAssignExp();
-	    ie = new ExpInitializer(loc, e);
-	    return ie;
-    }
-}
-
-
-/*****************************************
- * Input:
- *	flags	PSxxxx
- */
-
-Statement *Parser::parseStatement(int flags)
-{   Statement *s;
-    Token *t;
-    Condition *condition;
-    Statement *ifbody;
-    Statement *elsebody;
-    Loc loc = this->loc;
-
-    //printf("parseStatement()\n");
-
-    if (flags & PScurly && token.value != TOKlcurly)
-	error("statement expected to be { }, not %s", token.toChars());
-
-    switch (token.value)
-    {
-	case TOKidentifier:
-	    // Need to look ahead to see if it is a declaration, label, or expression
-	    t = peek(&token);
-	    if (t->value == TOKcolon)
-	    {	// It's a label
-		Identifier *ident;
-
-		ident = token.ident;
-		nextToken();
-		nextToken();
-		s = parseStatement(PSsemi);
-		s = new LabelStatement(loc, ident, s);
-		break;
-	    }
-	    // fallthrough to TOKdot
-	case TOKdot:
-	case TOKtypeof:
-	    if (isDeclaration(&token, 2, TOKreserved, NULL))
-		goto Ldeclaration;
-	    else
-		goto Lexp;
-	    break;
-
-	case TOKassert:
-	case TOKthis:
-	case TOKsuper:
-	case TOKint32v:
-	case TOKuns32v:
-	case TOKint64v:
-	case TOKuns64v:
-	case TOKfloat32v:
-	case TOKfloat64v:
-	case TOKfloat80v:
-	case TOKimaginary32v:
-	case TOKimaginary64v:
-	case TOKimaginary80v:
-	case TOKcharv:
-	case TOKwcharv:
-	case TOKdcharv:
-	case TOKnull:
-	case TOKtrue:
-	case TOKfalse:
-	case TOKstring:
-	case TOKlparen:
-	case TOKcast:
-	case TOKmul:
-	case TOKmin:
-	case TOKadd:
-	case TOKplusplus:
-	case TOKminusminus:
-	case TOKnew:
-	case TOKdelete:
-	case TOKdelegate:
-	case TOKfunction:
-	case TOKtypeid:
-	case TOKis:
-	case TOKlbracket:
-	Lexp:
-	{   Expression *exp;
-
-	    exp = parseExpression();
-	    check(TOKsemicolon, "statement");
-	    s = new ExpStatement(loc, exp);
-	    break;
-	}
-
-	case TOKstatic:
-	{   // Look ahead to see if it's static assert() or static if()
-	    Token *t;
-
-	    t = peek(&token);
-	    if (t->value == TOKassert)
-	    {
-		nextToken();
-		s = new StaticAssertStatement(parseStaticAssert());
-		break;
-	    }
-	    if (t->value == TOKif)
-	    {
-		nextToken();
-		condition = parseStaticIfCondition();
-		goto Lcondition;
-	    }
-	    goto Ldeclaration;
-	}
-
-	CASE_BASIC_TYPES:
-	case TOKtypedef:
-	case TOKalias:
-	case TOKconst:
-	case TOKauto:
-	case TOKextern:
-	case TOKfinal:
-	case TOKinvariant:
-//	case TOKtypeof:
-	Ldeclaration:
-	{   Array *a;
-
-	    a = parseDeclarations();
-	    if (a->dim > 1)
-	    {
-		Statements *as = new Statements();
-		as->reserve(a->dim);
-		for (int i = 0; i < a->dim; i++)
-		{
-		    Dsymbol *d = (Dsymbol *)a->data[i];
-		    s = new DeclarationStatement(loc, d);
-		    as->push(s);
-		}
-		s = new CompoundStatement(loc, as);
-	    }
-	    else if (a->dim == 1)
-	    {
-		Dsymbol *d = (Dsymbol *)a->data[0];
-		s = new DeclarationStatement(loc, d);
-	    }
-	    else
-		assert(0);
-	    if (flags & PSscope)
-		s = new ScopeStatement(loc, s);
-	    break;
-	}
-
-	case TOKstruct:
-	case TOKunion:
-	case TOKclass:
-	case TOKinterface:
-	{   Dsymbol *d;
-
-	    d = parseAggregate();
-	    s = new DeclarationStatement(loc, d);
-	    break;
-	}
-
-	case TOKenum:
-	{   Dsymbol *d;
-
-	    d = parseEnum();
-	    s = new DeclarationStatement(loc, d);
-	    break;
-	}
-
-	case TOKmixin:
-	{   t = peek(&token);
-	    if (t->value == TOKlparen)
-	    {	// mixin(string)
-		nextToken();
-		check(TOKlparen, "mixin");
-		Expression *e = parseAssignExp();
-		check(TOKrparen);
-		check(TOKsemicolon);
-		s = new CompileStatement(loc, e);
-		break;
-	    }
-	    Dsymbol *d = parseMixin();
-	    s = new DeclarationStatement(loc, d);
-	    break;
-	}
-
-	case TOKlcurly:
-	{   Statements *statements;
-
-	    nextToken();
-	    statements = new Statements();
-	    while (token.value != TOKrcurly)
-	    {
-		statements->push(parseStatement(PSsemi | PScurlyscope));
-	    }
-	    endloc = this->loc;
-	    s = new CompoundStatement(loc, statements);
-	    if (flags & (PSscope | PScurlyscope))
-		s = new ScopeStatement(loc, s);
-	    nextToken();
-	    break;
-	}
-
-	case TOKwhile:
-	{   Expression *condition;
-	    Statement *body;
-
-	    nextToken();
-	    check(TOKlparen);
-	    condition = parseExpression();
-	    check(TOKrparen);
-	    body = parseStatement(PSscope);
-	    s = new WhileStatement(loc, condition, body);
-	    break;
-	}
-
-	case TOKsemicolon:
-	    if (!(flags & PSsemi))
-		error("use '{ }' for an empty statement, not a ';'");
-	    nextToken();
-	    s = new ExpStatement(loc, NULL);
-	    break;
-
-	case TOKdo:
-	{   Statement *body;
-	    Expression *condition;
-
-	    nextToken();
-	    body = parseStatement(PSscope);
-	    check(TOKwhile);
-	    check(TOKlparen);
-	    condition = parseExpression();
-	    check(TOKrparen);
-	    s = new DoStatement(loc, body, condition);
-	    break;
-	}
-
-	case TOKfor:
-	{
-	    Statement *init;
-	    Expression *condition;
-	    Expression *increment;
-	    Statement *body;
-
-	    nextToken();
-	    check(TOKlparen);
-	    if (token.value == TOKsemicolon)
-	    {	init = NULL;
-		nextToken();
-	    }
-	    else
-	    {	init = parseStatement(0);
-	    }
-	    if (token.value == TOKsemicolon)
-	    {
-		condition = NULL;
-		nextToken();
-	    }
-	    else
-	    {
-		condition = parseExpression();
-		check(TOKsemicolon, "for condition");
-	    }
-	    if (token.value == TOKrparen)
-	    {	increment = NULL;
-		nextToken();
-	    }
-	    else
-	    {	increment = parseExpression();
-		check(TOKrparen);
-	    }
-	    body = parseStatement(PSscope);
-	    s = new ForStatement(loc, init, condition, increment, body);
-	    if (init)
-		s = new ScopeStatement(loc, s);
-	    break;
-	}
-
-	case TOKforeach:
-	case TOKforeach_reverse:
-	{
-	    enum TOK op = token.value;
-	    Arguments *arguments;
-
-	    Statement *d;
-	    Statement *body;
-	    Expression *aggr;
-
-	    nextToken();
-	    check(TOKlparen);
-
-	    arguments = new Arguments();
-
-	    while (1)
-	    {
-		Type *tb;
-		Identifier *ai = NULL;
-		Type *at;
-		unsigned storageClass;
-		Argument *a;
-
-		storageClass = STCin;
-		if (token.value == TOKinout || token.value == TOKref)
-		{   storageClass = STCref;
-		    nextToken();
-		}
-		if (token.value == TOKidentifier)
-		{
-		    Token *t = peek(&token);
-		    if (t->value == TOKcomma || t->value == TOKsemicolon)
-		    {	ai = token.ident;
-			at = NULL;		// infer argument type
-			nextToken();
-			goto Larg;
-		    }
-		}
-		tb = parseBasicType();
-		at = parseDeclarator(tb, &ai);
-		if (!ai)
-		    error("no identifier for declarator %s", at->toChars());
-	      Larg:
-		a = new Argument(storageClass, at, ai, NULL);
-		arguments->push(a);
-		if (token.value == TOKcomma)
-		{   nextToken();
-		    continue;
-		}
-		break;
-	    }
-	    check(TOKsemicolon);
-
-	    aggr = parseExpression();
-	    check(TOKrparen);
-	    body = parseStatement(0);
-	    s = new ForeachStatement(loc, op, arguments, aggr, body);
-	    break;
-	}
-
-	case TOKif:
-	{   Argument *arg = NULL;
-	    Expression *condition;
-	    Statement *ifbody;
-	    Statement *elsebody;
-
-	    nextToken();
-	    check(TOKlparen);
-
-	    if (token.value == TOKauto)
-	    {
-		nextToken();
-		if (token.value == TOKidentifier)
-		{
-		    Token *t = peek(&token);
-		    if (t->value == TOKassign)
-		    {
-			arg = new Argument(STCin, NULL, token.ident, NULL);
-			nextToken();
-			nextToken();
-		    }
-		    else
-		    {   error("= expected following auto identifier");
-			goto Lerror;
-		    }
-		}
-		else
-		{   error("identifier expected following auto");
-		    goto Lerror;
-		}
-	    }
-	    else if (isDeclaration(&token, 2, TOKassign, NULL))
-	    {
-		Type *tb;
-		Type *at;
-		Identifier *ai;
-
-		tb = parseBasicType();
-		at = parseDeclarator(tb, &ai);
-		check(TOKassign);
-		arg = new Argument(STCin, at, ai, NULL);
-	    }
-
-	    // Check for " ident;"
-	    else if (token.value == TOKidentifier)
-	    {
-		Token *t = peek(&token);
-		if (t->value == TOKcomma || t->value == TOKsemicolon)
-		{
-		    arg = new Argument(STCin, NULL, token.ident, NULL);
-		    nextToken();
-		    nextToken();
-		    if (1 || !global.params.useDeprecated)
-			error("if (v; e) is deprecated, use if (auto v = e)");
-		}
-	    }
-
-	    condition = parseExpression();
-	    check(TOKrparen);
-	    ifbody = parseStatement(PSscope);
-	    if (token.value == TOKelse)
-	    {
-		nextToken();
-		elsebody = parseStatement(PSscope);
-	    }
-	    else
-		elsebody = NULL;
-	    s = new IfStatement(loc, arg, condition, ifbody, elsebody);
-	    break;
-	}
-
-	case TOKscope:
-	    if (peek(&token)->value != TOKlparen)
-		goto Ldeclaration;		// scope used as storage class
-	    nextToken();
-	    check(TOKlparen);
-	    if (token.value != TOKidentifier)
-	    {	error("scope identifier expected");
-		goto Lerror;
-	    }
-	    else
-	    {	TOK t = TOKon_scope_exit;
-		Identifier *id = token.ident;
-
-		if (id == Id::exit)
-		    t = TOKon_scope_exit;
-		else if (id == Id::failure)
-		    t = TOKon_scope_failure;
-		else if (id == Id::success)
-		    t = TOKon_scope_success;
-		else
-		    error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
-		nextToken();
-		check(TOKrparen);
-		Statement *st = parseStatement(PScurlyscope);
-		s = new OnScopeStatement(loc, t, st);
-		break;
-	    }
-
-	case TOKdebug:
-	    nextToken();
-	    condition = parseDebugCondition();
-	    goto Lcondition;
-
-	case TOKversion:
-	    nextToken();
-	    condition = parseVersionCondition();
-	    goto Lcondition;
-
-	Lcondition:
-	    ifbody = parseStatement(0 /*PSsemi*/);
-	    elsebody = NULL;
-	    if (token.value == TOKelse)
-	    {
-		nextToken();
-		elsebody = parseStatement(0 /*PSsemi*/);
-	    }
-	    s = new ConditionalStatement(loc, condition, ifbody, elsebody);
-	    break;
-
-	case TOKpragma:
-	{   Identifier *ident;
-	    Expressions *args = NULL;
-	    Statement *body;
-
-	    nextToken();
-	    check(TOKlparen);
-	    if (token.value != TOKidentifier)
-	    {   error("pragma(identifier expected");
-		goto Lerror;
-	    }
-	    ident = token.ident;
-	    nextToken();
-	    if (token.value == TOKcomma)
-		args = parseArguments();	// pragma(identifier, args...);
-	    else
-		check(TOKrparen);		// pragma(identifier);
-	    if (token.value == TOKsemicolon)
-	    {	nextToken();
-		body = NULL;
-	    }
-	    else
-		body = parseStatement(PSsemi);
-	    s = new PragmaStatement(loc, ident, args, body);
-	    break;
-	}
-
-	case TOKswitch:
-	{   Expression *condition;
-	    Statement *body;
-
-	    nextToken();
-	    check(TOKlparen);
-	    condition = parseExpression();
-	    check(TOKrparen);
-	    body = parseStatement(PSscope);
-	    s = new SwitchStatement(loc, condition, body);
-	    break;
-	}
-
-	case TOKcase:
-	{   Expression *exp;
-	    Statements *statements;
-	    Array cases;	// array of Expression's
-
-	    while (1)
-	    {
-		nextToken();
-		exp = parseAssignExp();
-		cases.push(exp);
-		if (token.value != TOKcomma)
-		    break;
-	    }
-	    check(TOKcolon);
-
-	    statements = new Statements();
-	    while (token.value != TOKcase &&
-		   token.value != TOKdefault &&
-		   token.value != TOKrcurly)
-	    {
-		statements->push(parseStatement(PSsemi | PScurlyscope));
-	    }
-	    s = new CompoundStatement(loc, statements);
-	    s = new ScopeStatement(loc, s);
-
-	    // Keep cases in order by building the case statements backwards
-	    for (int i = cases.dim; i; i--)
-	    {
-		exp = (Expression *)cases.data[i - 1];
-		s = new CaseStatement(loc, exp, s);
-	    }
-	    break;
-	}
-
-	case TOKdefault:
-	{
-	    Statements *statements;
-
-	    nextToken();
-	    check(TOKcolon);
-
-	    statements = new Statements();
-	    while (token.value != TOKcase &&
-		   token.value != TOKdefault &&
-		   token.value != TOKrcurly)
-	    {
-		statements->push(parseStatement(PSsemi | PScurlyscope));
-	    }
-	    s = new CompoundStatement(loc, statements);
-	    s = new ScopeStatement(loc, s);
-	    s = new DefaultStatement(loc, s);
-	    break;
-	}
-
-	case TOKreturn:
-	{   Expression *exp;
-
-	    nextToken();
-	    if (token.value == TOKsemicolon)
-		exp = NULL;
-	    else
-		exp = parseExpression();
-	    check(TOKsemicolon, "return statement");
-	    s = new ReturnStatement(loc, exp);
-	    break;
-	}
-
-	case TOKbreak:
-	{   Identifier *ident;
-
-	    nextToken();
-	    if (token.value == TOKidentifier)
-	    {	ident = token.ident;
-		nextToken();
-	    }
-	    else
-		ident = NULL;
-	    check(TOKsemicolon, "break statement");
-	    s = new BreakStatement(loc, ident);
-	    break;
-	}
-
-	case TOKcontinue:
-	{   Identifier *ident;
-
-	    nextToken();
-	    if (token.value == TOKidentifier)
-	    {	ident = token.ident;
-		nextToken();
-	    }
-	    else
-		ident = NULL;
-	    check(TOKsemicolon, "continue statement");
-	    s = new ContinueStatement(loc, ident);
-	    break;
-	}
-
-	case TOKgoto:
-	{   Identifier *ident;
-
-	    nextToken();
-	    if (token.value == TOKdefault)
-	    {
-		nextToken();
-		s = new GotoDefaultStatement(loc);
-	    }
-	    else if (token.value == TOKcase)
-	    {
-		Expression *exp = NULL;
-
-		nextToken();
-		if (token.value != TOKsemicolon)
-		    exp = parseExpression();
-		s = new GotoCaseStatement(loc, exp);
-	    }
-	    else
-	    {
-		if (token.value != TOKidentifier)
-		{   error("Identifier expected following goto");
-		    ident = NULL;
-		}
-		else
-		{   ident = token.ident;
-		    nextToken();
-		}
-		s = new GotoStatement(loc, ident);
-	    }
-	    check(TOKsemicolon, "goto statement");
-	    break;
-	}
-
-	case TOKsynchronized:
-	{   Expression *exp;
-	    Statement *body;
-
-	    nextToken();
-	    if (token.value == TOKlparen)
-	    {
-		nextToken();
-		exp = parseExpression();
-		check(TOKrparen);
-	    }
-	    else
-		exp = NULL;
-	    body = parseStatement(PSscope);
-	    s = new SynchronizedStatement(loc, exp, body);
-	    break;
-	}
-
-	case TOKwith:
-	{   Expression *exp;
-	    Statement *body;
-
-	    nextToken();
-	    check(TOKlparen);
-	    exp = parseExpression();
-	    check(TOKrparen);
-	    body = parseStatement(PSscope);
-	    s = new WithStatement(loc, exp, body);
-	    break;
-	}
-
-	case TOKtry:
-	{   Statement *body;
-	    Array *catches = NULL;
-	    Statement *finalbody = NULL;
-
-	    nextToken();
-	    body = parseStatement(PSscope);
-	    while (token.value == TOKcatch)
-	    {
-		Statement *handler;
-		Catch *c;
-		Type *t;
-		Identifier *id;
-		Loc loc = this->loc;
-
-		nextToken();
-		if (token.value == TOKlcurly)
-		{
-		    t = NULL;
-		    id = NULL;
-		}
-		else
-		{
-		    check(TOKlparen);
-		    t = parseBasicType();
-		    id = NULL;
-		    t = parseDeclarator(t, &id);
-		    check(TOKrparen);
-		}
-		handler = parseStatement(0);
-		c = new Catch(loc, t, id, handler);
-		if (!catches)
-		    catches = new Array();
-		catches->push(c);
-	    }
-
-	    if (token.value == TOKfinally)
-	    {	nextToken();
-		finalbody = parseStatement(0);
-	    }
-
-	    s = body;
-	    if (!catches && !finalbody)
-		error("catch or finally expected following try");
-	    else
-	    {	if (catches)
-		    s = new TryCatchStatement(loc, body, catches);
-		if (finalbody)
-		    s = new TryFinallyStatement(loc, s, finalbody);
-	    }
-	    break;
-	}
-
-	case TOKthrow:
-	{   Expression *exp;
-
-	    nextToken();
-	    exp = parseExpression();
-	    check(TOKsemicolon, "throw statement");
-	    s = new ThrowStatement(loc, exp);
-	    break;
-	}
-
-	case TOKvolatile:
-	    nextToken();
-	    s = parseStatement(PSsemi | PScurlyscope);
-	    s = new VolatileStatement(loc, s);
-	    break;
-
-	case TOKasm:
-	{   Statements *statements;
-	    Identifier *label;
-	    Loc labelloc;
-	    Token *toklist;
-	    Token **ptoklist;
-
-	    // Parse the asm block into a sequence of AsmStatements,
-	    // each AsmStatement is one instruction.
-	    // Separate out labels.
-	    // Defer parsing of AsmStatements until semantic processing.
-
-	    nextToken();
-	    check(TOKlcurly);
-	    toklist = NULL;
-	    ptoklist = &toklist;
-	    label = NULL;
-	    statements = new Statements();
-	    while (1)
-	    {
-		switch (token.value)
-		{
-		    case TOKidentifier:
-			if (!toklist)
-			{
-			    // Look ahead to see if it is a label
-			    t = peek(&token);
-			    if (t->value == TOKcolon)
-			    {   // It's a label
-				label = token.ident;
-				labelloc = this->loc;
-				nextToken();
-				nextToken();
-				continue;
-			    }
-			}
-			goto Ldefault;
-
-		    case TOKrcurly:
-			if (toklist || label)
-			{
-			    error("asm statements must end in ';'");
-			}
-			break;
-
-		    case TOKsemicolon:
-			s = NULL;
-			if (toklist || label)
-			{   // Create AsmStatement from list of tokens we've saved
-			    s = new AsmStatement(this->loc, toklist);
-			    toklist = NULL;
-			    ptoklist = &toklist;
-			    if (label)
-			    {   s = new LabelStatement(labelloc, label, s);
-				label = NULL;
-			    }
-			    statements->push(s);
-			}
-			nextToken();
-			continue;
-
-		    case TOKeof:
-			/* { */
-			error("matching '}' expected, not end of file");
-			break;
-
-		    default:
-		    Ldefault:
-			*ptoklist = new Token();
-			memcpy(*ptoklist, &token, sizeof(Token));
-			ptoklist = &(*ptoklist)->next;
-			*ptoklist = NULL;
-
-			nextToken();
-			continue;
-		}
-		break;
-	    }
-        s = new AsmBlockStatement(loc, statements);
-	    nextToken();
-	    break;
-	}
-
-	default:
-	    error("found '%s' instead of statement", token.toChars());
-	    goto Lerror;
-
-	Lerror:
-	    while (token.value != TOKrcurly &&
-		   token.value != TOKsemicolon &&
-		   token.value != TOKeof)
-		nextToken();
-	    if (token.value == TOKsemicolon)
-		nextToken();
-	    s = NULL;
-	    break;
-    }
-
-    return s;
-}
-
-void Parser::check(enum TOK value)
-{
-    check(loc, value);
-}
-
-void Parser::check(Loc loc, enum TOK value)
-{
-    if (token.value != value)
-	error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
-    nextToken();
-}
-
-void Parser::check(enum TOK value, char *string)
-{
-    if (token.value != value)
-	error("found '%s' when expecting '%s' following '%s'",
-	    token.toChars(), Token::toChars(value), string);
-    nextToken();
-}
-
-/************************************
- * Determine if the scanner is sitting on the start of a declaration.
- * Input:
- *	needId	0	no identifier
- *		1	identifier optional
- *		2	must have identifier
- */
-
-int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
-{
-    int haveId = 0;
-
-    if (!isBasicType(&t))
-	return FALSE;
-    if (!isDeclarator(&t, &haveId, endtok))
-	return FALSE;
-    if ( needId == 1 ||
-	(needId == 0 && !haveId) ||
-	(needId == 2 &&  haveId))
-    {	if (pt)
-	    *pt = t;
-	return TRUE;
-    }
-    else
-	return FALSE;
-}
-
-int Parser::isBasicType(Token **pt)
-{
-    // This code parallels parseBasicType()
-    Token *t = *pt;
-    Token *t2;
-    int parens;
-
-    switch (t->value)
-    {
-	CASE_BASIC_TYPES:
-	    t = peek(t);
-	    break;
-
-	case TOKidentifier:
-	    t = peek(t);
-	    if (t->value == TOKnot)
-	    {
-		goto L4;
-	    }
-	    goto L3;
-	    while (1)
-	    {
-	L2:
-		t = peek(t);
-	L3:
-		if (t->value == TOKdot)
-		{
-	Ldot:
-		    t = peek(t);
-		    if (t->value != TOKidentifier)
-			goto Lfalse;
-		    t = peek(t);
-		    if (t->value != TOKnot)
-			goto L3;
-	L4:
-		    t = peek(t);
-		    if (t->value != TOKlparen)
-			goto Lfalse;
-		    if (!skipParens(t, &t))
-			goto Lfalse;
-		}
-		else
-		    break;
-	    }
-	    break;
-
-	case TOKdot:
-	    goto Ldot;
-
-	case TOKtypeof:
-	    /* typeof(exp).identifier...
-	     */
-	    t = peek(t);
-	    if (t->value != TOKlparen)
-		goto Lfalse;
-	    if (!skipParens(t, &t))
-		goto Lfalse;
-	    goto L2;
-
-	default:
-	    goto Lfalse;
-    }
-    *pt = t;
-    return TRUE;
-
-Lfalse:
-    return FALSE;
-}
-
-int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
-{   // This code parallels parseDeclarator()
-    Token *t = *pt;
-    int parens;
-
-    //printf("Parser::isDeclarator()\n");
-    //t->print();
-    if (t->value == TOKassign)
-	return FALSE;
-
-    while (1)
-    {
-	parens = FALSE;
-	switch (t->value)
-	{
-	    case TOKmul:
-	    case TOKand:
-		t = peek(t);
-		continue;
-
-	    case TOKlbracket:
-		t = peek(t);
-		if (t->value == TOKrbracket)
-		{
-		    t = peek(t);
-		}
-		else if (isDeclaration(t, 0, TOKrbracket, &t))
-		{   // It's an associative array declaration
-		    t = peek(t);
-		}
-		else
-		{
-		    // [ expression ]
-		    // [ expression .. expression ]
-		    if (!isExpression(&t))
-			return FALSE;
-		    if (t->value == TOKslice)
-		    {	t = peek(t);
-			if (!isExpression(&t))
-			    return FALSE;
-		    }
-		    if (t->value != TOKrbracket)
-			return FALSE;
-		    t = peek(t);
-		}
-		continue;
-
-	    case TOKidentifier:
-		if (*haveId)
-		    return FALSE;
-		*haveId = TRUE;
-		t = peek(t);
-		break;
-
-	    case TOKlparen:
-		t = peek(t);
-
-		if (t->value == TOKrparen)
-		    return FALSE;		// () is not a declarator
-
-		/* Regard ( identifier ) as not a declarator
-		 * BUG: what about ( *identifier ) in
-		 *	f(*p)(x);
-		 * where f is a class instance with overloaded () ?
-		 * Should we just disallow C-style function pointer declarations?
-		 */
-		if (t->value == TOKidentifier)
-		{   Token *t2 = peek(t);
-		    if (t2->value == TOKrparen)
-			return FALSE;
-		}
-
-
-		if (!isDeclarator(&t, haveId, TOKrparen))
-		    return FALSE;
-		t = peek(t);
-		parens = TRUE;
-		break;
-
-	    case TOKdelegate:
-	    case TOKfunction:
-		t = peek(t);
-		if (!isParameters(&t))
-		    return FALSE;
-		continue;
-	}
-	break;
-    }
-
-    while (1)
-    {
-	switch (t->value)
-	{
-#if CARRAYDECL
-	    case TOKlbracket:
-		parens = FALSE;
-		t = peek(t);
-		if (t->value == TOKrbracket)
-		{
-		    t = peek(t);
-		}
-		else if (isDeclaration(t, 0, TOKrbracket, &t))
-		{   // It's an associative array declaration
-		    t = peek(t);
-		}
-		else
-		{
-		    // [ expression ]
-		    if (!isExpression(&t))
-			return FALSE;
-		    if (t->value != TOKrbracket)
-			return FALSE;
-		    t = peek(t);
-		}
-		continue;
-#endif
-
-	    case TOKlparen:
-		parens = FALSE;
-		if (!isParameters(&t))
-		    return FALSE;
-		continue;
-
-	    // Valid tokens that follow a declaration
-	    case TOKrparen:
-	    case TOKrbracket:
-	    case TOKassign:
-	    case TOKcomma:
-	    case TOKsemicolon:
-	    case TOKlcurly:
-	    case TOKin:
-		// The !parens is to disallow unnecessary parentheses
-		if (!parens && (endtok == TOKreserved || endtok == t->value))
-		{   *pt = t;
-		    return TRUE;
-		}
-		return FALSE;
-
-	    default:
-		return FALSE;
-	}
-    }
-}
-
-
-int Parser::isParameters(Token **pt)
-{   // This code parallels parseParameters()
-    Token *t = *pt;
-    int tmp;
-
-    //printf("isParameters()\n");
-    if (t->value != TOKlparen)
-	return FALSE;
-
-    t = peek(t);
-    while (1)
-    {
-	switch (t->value)
-	{
-	    case TOKrparen:
-		break;
-
-	    case TOKdotdotdot:
-		t = peek(t);
-		break;
-
-	    case TOKin:
-	    case TOKout:
-	    case TOKinout:
-	    case TOKref:
-	    case TOKlazy:
-		t = peek(t);
-	    default:
-		if (!isBasicType(&t))
-		    return FALSE;
-		tmp = FALSE;
-		if (t->value != TOKdotdotdot &&
-		    !isDeclarator(&t, &tmp, TOKreserved))
-		    return FALSE;
-		if (t->value == TOKassign)
-		{   t = peek(t);
-		    if (!isExpression(&t))
-			return FALSE;
-		}
-		if (t->value == TOKdotdotdot)
-		{
-		    t = peek(t);
-		    break;
-		}
-		if (t->value == TOKcomma)
-		{   t = peek(t);
-		    continue;
-		}
-		break;
-	}
-	break;
-    }
-    if (t->value != TOKrparen)
-	return FALSE;
-    t = peek(t);
-    *pt = t;
-    return TRUE;
-}
-
-int Parser::isExpression(Token **pt)
-{
-    // This is supposed to determine if something is an expression.
-    // What it actually does is scan until a closing right bracket
-    // is found.
-
-    Token *t = *pt;
-    int brnest = 0;
-    int panest = 0;
-
-    for (;; t = peek(t))
-    {
-	switch (t->value)
-	{
-	    case TOKlbracket:
-		brnest++;
-		continue;
-
-	    case TOKrbracket:
-		if (--brnest >= 0)
-		    continue;
-		break;
-
-	    case TOKlparen:
-		panest++;
-		continue;
-
-	    case TOKcomma:
-		if (brnest || panest)
-		    continue;
-		break;
-
-	    case TOKrparen:
-		if (--panest >= 0)
-		    continue;
-		break;
-
-	    case TOKslice:
-		if (brnest)
-		    continue;
-		break;
-
-	    case TOKeof:
-		return FALSE;
-
-	    default:
-		continue;
-	}
-	break;
-    }
-
-    *pt = t;
-    return TRUE;
-}
-
-/**********************************************
- * Skip over
- *	instance foo.bar(parameters...)
- * Output:
- *	if (pt), *pt is set to the token following the closing )
- * Returns:
- *	1	it's valid instance syntax
- *	0	invalid instance syntax
- */
-
-int Parser::isTemplateInstance(Token *t, Token **pt)
-{
-    t = peek(t);
-    if (t->value != TOKdot)
-    {
-	if (t->value != TOKidentifier)
-	    goto Lfalse;
-	t = peek(t);
-    }
-    while (t->value == TOKdot)
-    {
-	t = peek(t);
-	if (t->value != TOKidentifier)
-	    goto Lfalse;
-	t = peek(t);
-    }
-    if (t->value != TOKlparen)
-	goto Lfalse;
-
-    // Skip over the template arguments
-    while (1)
-    {
-	while (1)
-	{
-	    t = peek(t);
-	    switch (t->value)
-	    {
-		case TOKlparen:
-		    if (!skipParens(t, &t))
-			goto Lfalse;
-		    continue;
-		case TOKrparen:
-		    break;
-		case TOKcomma:
-		    break;
-		case TOKeof:
-		case TOKsemicolon:
-		    goto Lfalse;
-		default:
-		    continue;
-	    }
-	    break;
-	}
-
-	if (t->value != TOKcomma)
-	    break;
-    }
-    if (t->value != TOKrparen)
-	goto Lfalse;
-    t = peek(t);
-    if (pt)
-	*pt = t;
-    return 1;
-
-Lfalse:
-    return 0;
-}
-
-/*******************************************
- * Skip parens, brackets.
- * Input:
- *	t is on opening (
- * Output:
- *	*pt is set to closing token, which is ')' on success
- * Returns:
- *	!=0	successful
- *	0	some parsing error
- */
-
-int Parser::skipParens(Token *t, Token **pt)
-{
-    int parens = 0;
-
-    while (1)
-    {
-	switch (t->value)
-	{
-	    case TOKlparen:
-		parens++;
-		break;
-
-	    case TOKrparen:
-		parens--;
-		if (parens < 0)
-		    goto Lfalse;
-		if (parens == 0)
-		    goto Ldone;
-		break;
-
-	    case TOKeof:
-	    case TOKsemicolon:
-		goto Lfalse;
-
-	     default:
-		break;
-	}
-	t = peek(t);
-    }
-
-  Ldone:
-    if (*pt)
-	*pt = t;
-    return 1;
-
-  Lfalse:
-    return 0;
-}
-
-/********************************* Expression Parser ***************************/
-
-Expression *Parser::parsePrimaryExp()
-{   Expression *e;
-    Type *t;
-    Identifier *id;
-    enum TOK save;
-    Loc loc = this->loc;
-
-    switch (token.value)
-    {
-	case TOKidentifier:
-	    id = token.ident;
-	    nextToken();
-	    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
-	    {	// identifier!(template-argument-list)
-		TemplateInstance *tempinst;
-
-		tempinst = new TemplateInstance(loc, id);
-		nextToken();
-		tempinst->tiargs = parseTemplateArgumentList();
-		e = new ScopeExp(loc, tempinst);
-	    }
-	    else
-		e = new IdentifierExp(loc, id);
-	    break;
-
-	case TOKdollar:
-	    if (!inBrackets)
-		error("'$' is valid only inside [] of index or slice");
-	    e = new DollarExp(loc);
-	    nextToken();
-	    break;
-
-	case TOKdot:
-	    // Signal global scope '.' operator with "" identifier
-	    e = new IdentifierExp(loc, Id::empty);
-	    break;
-
-	case TOKthis:
-	    e = new ThisExp(loc);
-	    nextToken();
-	    break;
-
-	case TOKsuper:
-	    e = new SuperExp(loc);
-	    nextToken();
-	    break;
-
-	case TOKint32v:
-	    e = new IntegerExp(loc, token.int32value, Type::tint32);
-	    nextToken();
-	    break;
-
-	case TOKuns32v:
-	    e = new IntegerExp(loc, token.uns32value, Type::tuns32);
-	    nextToken();
-	    break;
-
-	case TOKint64v:
-	    e = new IntegerExp(loc, token.int64value, Type::tint64);
-	    nextToken();
-	    break;
-
-	case TOKuns64v:
-	    e = new IntegerExp(loc, token.uns64value, Type::tuns64);
-	    nextToken();
-	    break;
-
-	case TOKfloat32v:
-	    e = new RealExp(loc, token.float80value, Type::tfloat32);
-	    nextToken();
-	    break;
-
-	case TOKfloat64v:
-	    e = new RealExp(loc, token.float80value, Type::tfloat64);
-	    nextToken();
-	    break;
-
-	case TOKfloat80v:
-	    e = new RealExp(loc, token.float80value, Type::tfloat80);
-	    nextToken();
-	    break;
-
-	case TOKimaginary32v:
-	    e = new RealExp(loc, token.float80value, Type::timaginary32);
-	    nextToken();
-	    break;
-
-	case TOKimaginary64v:
-	    e = new RealExp(loc, token.float80value, Type::timaginary64);
-	    nextToken();
-	    break;
-
-	case TOKimaginary80v:
-	    e = new RealExp(loc, token.float80value, Type::timaginary80);
-	    nextToken();
-	    break;
-
-	case TOKnull:
-	    e = new NullExp(loc);
-	    nextToken();
-	    break;
-
-	case TOKtrue:
-	    e = new IntegerExp(loc, 1, Type::tbool);
-	    nextToken();
-	    break;
-
-	case TOKfalse:
-	    e = new IntegerExp(loc, 0, Type::tbool);
-	    nextToken();
-	    break;
-
-	case TOKcharv:
-	    e = new IntegerExp(loc, token.uns32value, Type::tchar);
-	    nextToken();
-	    break;
-
-	case TOKwcharv:
-	    e = new IntegerExp(loc, token.uns32value, Type::twchar);
-	    nextToken();
-	    break;
-
-	case TOKdcharv:
-	    e = new IntegerExp(loc, token.uns32value, Type::tdchar);
-	    nextToken();
-	    break;
-
-	case TOKstring:
-	{   unsigned char *s;
-	    unsigned len;
-	    unsigned char postfix;
-
-	    // cat adjacent strings
-	    s = token.ustring;
-	    len = token.len;
-	    postfix = token.postfix;
-	    while (1)
-	    {
-		nextToken();
-		if (token.value == TOKstring)
-		{   unsigned len1;
-		    unsigned len2;
-		    unsigned char *s2;
-
-		    if (token.postfix)
-		    {	if (token.postfix != postfix)
-			    error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
-			postfix = token.postfix;
-		    }
-
-		    len1 = len;
-		    len2 = token.len;
-		    len = len1 + len2;
-		    s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
-		    memcpy(s2, s, len1 * sizeof(unsigned char));
-		    memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
-		    s = s2;
-		}
-		else
-		    break;
-	    }
-	    e = new StringExp(loc, s, len, postfix);
-	    break;
-	}
-
-	CASE_BASIC_TYPES_X(t):
-	    nextToken();
-	L1:
-	    check(TOKdot, t->toChars());
-	    if (token.value != TOKidentifier)
-	    {   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
-		goto Lerr;
-	    }
-	    e = new TypeDotIdExp(loc, t, token.ident);
-	    nextToken();
-	    break;
-
-	case TOKtypeof:
-	{   Expression *exp;
-
-	    nextToken();
-	    check(TOKlparen);
-	    exp = parseExpression();
-	    check(TOKrparen);
-	    t = new TypeTypeof(loc, exp);
-	    if (token.value == TOKdot)
-		goto L1;
-	    e = new TypeExp(loc, t);
-	    break;
-	}
-
-	case TOKtypeid:
-	{   Type *t;
-
-	    nextToken();
-	    check(TOKlparen, "typeid");
-	    t = parseBasicType();
-	    t = parseDeclarator(t,NULL);	// ( type )
-	    check(TOKrparen);
-	    e = new TypeidExp(loc, t);
-	    break;
-	}
-
-	case TOKis:
-	{   Type *targ;
-	    Identifier *ident = NULL;
-	    Type *tspec = NULL;
-	    enum TOK tok = TOKreserved;
-	    enum TOK tok2 = TOKreserved;
-	    Loc loc = this->loc;
-
-	    nextToken();
-	    if (token.value == TOKlparen)
-	    {
-		nextToken();
-		targ = parseBasicType();
-		targ = parseDeclarator(targ, &ident);
-		if (token.value == TOKcolon || token.value == TOKequal)
-		{
-		    tok = token.value;
-		    nextToken();
-		    if (tok == TOKequal &&
-			(token.value == TOKtypedef ||
-			 token.value == TOKstruct ||
-			 token.value == TOKunion ||
-			 token.value == TOKclass ||
-			 token.value == TOKsuper ||
-			 token.value == TOKenum ||
-			 token.value == TOKinterface ||
-			 token.value == TOKfunction ||
-			 token.value == TOKdelegate ||
-			 token.value == TOKreturn))
-		    {
-			tok2 = token.value;
-			nextToken();
-		    }
-		    else
-		    {
-			tspec = parseBasicType();
-			tspec = parseDeclarator(tspec, NULL);
-		    }
-		}
-		check(TOKrparen);
-	    }
-	    else
-	    {   error("(type identifier : specialization) expected following is");
-		goto Lerr;
-	    }
-	    e = new IsExp(loc, targ, ident, tok, tspec, tok2);
-	    break;
-	}
-
-	case TOKassert:
-	{   Expression *msg = NULL;
-
-	    nextToken();
-	    check(TOKlparen, "assert");
-	    e = parseAssignExp();
-	    if (token.value == TOKcomma)
-	    {	nextToken();
-		msg = parseAssignExp();
-	    }
-	    check(TOKrparen);
-	    e = new AssertExp(loc, e, msg);
-	    break;
-	}
-
-	case TOKmixin:
-	{
-	    nextToken();
-	    check(TOKlparen, "mixin");
-	    e = parseAssignExp();
-	    check(TOKrparen);
-	    e = new CompileExp(loc, e);
-	    break;
-	}
-
-	case TOKimport:
-	{
-	    nextToken();
-	    check(TOKlparen, "import");
-	    e = parseAssignExp();
-	    check(TOKrparen);
-	    e = new FileExp(loc, e);
-	    break;
-	}
-
-	case TOKlparen:
-	    if (peekPastParen(&token)->value == TOKlcurly)
-	    {	// (arguments) { statements... }
-		save = TOKdelegate;
-		goto case_delegate;
-	    }
-	    // ( expression )
-	    nextToken();
-	    e = parseExpression();
-	    check(loc, TOKrparen);
-	    break;
-
-	case TOKlbracket:
-	{   /* Parse array literals and associative array literals:
-	     *	[ value, value, value ... ]
-	     *	[ key:value, key:value, key:value ... ]
-	     */
-	    Expressions *values = new Expressions();
-	    Expressions *keys = NULL;
-
-	    nextToken();
-	    if (token.value != TOKrbracket)
-	    {
-		while (1)
-		{
-		    Expression *e = parseAssignExp();
-		    if (token.value == TOKcolon && (keys || values->dim == 0))
-		    {	nextToken();
-			if (!keys)
-			    keys = new Expressions();
-			keys->push(e);
-			e = parseAssignExp();
-		    }
-		    else if (keys)
-		    {	error("'key:value' expected for associative array literal");
-			delete keys;
-			keys = NULL;
-		    }
-		    values->push(e);
-		    if (token.value == TOKrbracket)
-			break;
-		    check(TOKcomma);
-		}
-	    }
-	    check(TOKrbracket);
-
-	    if (keys)
-		e = new AssocArrayLiteralExp(loc, keys, values);
-	    else
-		e = new ArrayLiteralExp(loc, values);
-	    break;
-	}
-
-	case TOKlcurly:
-	    // { statements... }
-	    save = TOKdelegate;
-	    goto case_delegate;
-
-	case TOKfunction:
-	case TOKdelegate:
-	    save = token.value;
-	    nextToken();
-	case_delegate:
-	{
-	    /* function type(parameters) { body }
-	     * delegate type(parameters) { body }
-	     */
-	    Arguments *arguments;
-	    int varargs;
-	    FuncLiteralDeclaration *fd;
-	    Type *t;
-
-	    if (token.value == TOKlcurly)
-	    {
-		t = NULL;
-		varargs = 0;
-		arguments = new Arguments();
-	    }
-	    else
-	    {
-		if (token.value == TOKlparen)
-		    t = NULL;
-		else
-		{
-		    t = parseBasicType();
-		    t = parseBasicType2(t);	// function return type
-		}
-		arguments = parseParameters(&varargs);
-	    }
-	    t = new TypeFunction(arguments, t, varargs, linkage);
-	    fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL);
-	    parseContracts(fd);
-	    e = new FuncExp(loc, fd);
-	    break;
-	}
-
-	default:
-	    error("expression expected, not '%s'", token.toChars());
-	Lerr:
-	    // Anything for e, as long as it's not NULL
-	    e = new IntegerExp(loc, 0, Type::tint32);
-	    nextToken();
-	    break;
-    }
-    return parsePostExp(e);
-}
-
-Expression *Parser::parsePostExp(Expression *e)
-{
-    Loc loc;
-
-    while (1)
-    {
-	loc = this->loc;
-	switch (token.value)
-	{
-	    case TOKdot:
-		nextToken();
-		if (token.value == TOKidentifier)
-		{   Identifier *id = token.ident;
-
-		    nextToken();
-		    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
-		    {   // identifier!(template-argument-list)
-			TemplateInstance *tempinst;
-
-			tempinst = new TemplateInstance(loc, id);
-			nextToken();
-			tempinst->tiargs = parseTemplateArgumentList();
-			e = new DotTemplateInstanceExp(loc, e, tempinst);
-		    }
-		    else
-			e = new DotIdExp(loc, e, id);
-		    continue;
-		}
-		else if (token.value == TOKnew)
-		{
-		    e = parseNewExp(e);
-		    continue;
-		}
-		else
-		    error("identifier expected following '.', not '%s'", token.toChars());
-		break;
-
-	    case TOKplusplus:
-		e = new PostExp(TOKplusplus, loc, e);
-		break;
-
-	    case TOKminusminus:
-		e = new PostExp(TOKminusminus, loc, e);
-		break;
-
-	    case TOKlparen:
-		e = new CallExp(loc, e, parseArguments());
-		continue;
-
-	    case TOKlbracket:
-	    {	// array dereferences:
-		//	array[index]
-		//	array[]
-		//	array[lwr .. upr]
-		Expression *index;
-		Expression *upr;
-
-		inBrackets++;
-		nextToken();
-		if (token.value == TOKrbracket)
-		{   // array[]
-		    e = new SliceExp(loc, e, NULL, NULL);
-		    nextToken();
-		}
-		else
-		{
-		    index = parseAssignExp();
-		    if (token.value == TOKslice)
-		    {	// array[lwr .. upr]
-			nextToken();
-			upr = parseAssignExp();
-			e = new SliceExp(loc, e, index, upr);
-		    }
-		    else
-		    {	// array[index, i2, i3, i4, ...]
-			Expressions *arguments = new Expressions();
-			arguments->push(index);
-			if (token.value == TOKcomma)
-			{
-			    nextToken();
-			    while (1)
-			    {   Expression *arg;
-
-				arg = parseAssignExp();
-				arguments->push(arg);
-				if (token.value == TOKrbracket)
-				    break;
-				check(TOKcomma);
-			    }
-			}
-			e = new ArrayExp(loc, e, arguments);
-		    }
-		    check(TOKrbracket);
-		    inBrackets--;
-		}
-		continue;
-	    }
-
-	    default:
-		return e;
-	}
-	nextToken();
-    }
-}
-
-Expression *Parser::parseUnaryExp()
-{   Expression *e;
-    Loc loc = this->loc;
-
-    switch (token.value)
-    {
-	case TOKand:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new AddrExp(loc, e);
-	    break;
-
-	case TOKplusplus:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
-	    break;
-
-	case TOKminusminus:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
-	    break;
-
-	case TOKmul:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new PtrExp(loc, e);
-	    break;
-
-	case TOKmin:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new NegExp(loc, e);
-	    break;
-
-	case TOKadd:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new UAddExp(loc, e);
-	    break;
-
-	case TOKnot:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new NotExp(loc, e);
-	    break;
-
-	case TOKtilde:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new ComExp(loc, e);
-	    break;
-
-	case TOKdelete:
-	    nextToken();
-	    e = parseUnaryExp();
-	    e = new DeleteExp(loc, e);
-	    break;
-
-	case TOKnew:
-	    e = parseNewExp(NULL);
-	    break;
-
-	case TOKcast:				// cast(type) expression
-	{   Type *t;
-
-	    nextToken();
-	    check(TOKlparen);
-	    t = parseBasicType();
-	    t = parseDeclarator(t,NULL);	// ( type )
-	    check(TOKrparen);
-
-	    e = parseUnaryExp();
-	    e = new CastExp(loc, e, t);
-	    break;
-	}
-
-	case TOKlparen:
-	{   Token *tk;
-
-	    tk = peek(&token);
-#if CCASTSYNTAX
-	    // If cast
-	    if (isDeclaration(tk, 0, TOKrparen, &tk))
-	    {
-		tk = peek(tk);		// skip over right parenthesis
-		switch (tk->value)
-		{
-		    case TOKdot:
-		    case TOKplusplus:
-		    case TOKminusminus:
-		    case TOKnot:
-		    case TOKdelete:
-		    case TOKnew:
-		    case TOKlparen:
-		    case TOKidentifier:
-		    case TOKthis:
-		    case TOKsuper:
-		    case TOKint32v:
-		    case TOKuns32v:
-		    case TOKint64v:
-		    case TOKuns64v:
-		    case TOKfloat32v:
-		    case TOKfloat64v:
-		    case TOKfloat80v:
-		    case TOKimaginary32v:
-		    case TOKimaginary64v:
-		    case TOKimaginary80v:
-		    case TOKnull:
-		    case TOKtrue:
-		    case TOKfalse:
-		    case TOKcharv:
-		    case TOKwcharv:
-		    case TOKdcharv:
-		    case TOKstring:
-#if 0
-		    case TOKtilde:
-		    case TOKand:
-		    case TOKmul:
-		    case TOKmin:
-		    case TOKadd:
-#endif
-		    case TOKfunction:
-		    case TOKdelegate:
-		    case TOKtypeof:
-		    CASE_BASIC_TYPES:		// (type)int.size
-		    {	// (type) una_exp
-			Type *t;
-
-			nextToken();
-			t = parseBasicType();
-			t = parseDeclarator(t,NULL);
-			check(TOKrparen);
-
-			// if .identifier
-			if (token.value == TOKdot)
-			{
-			    nextToken();
-			    if (token.value != TOKidentifier)
-			    {   error("Identifier expected following (type).");
-				return NULL;
-			    }
-			    e = new TypeDotIdExp(loc, t, token.ident);
-			    nextToken();
-			    e = parsePostExp(e);
-			}
-			else
-			{
-			    e = parseUnaryExp();
-			    e = new CastExp(loc, e, t);
-			    error("C style cast illegal, use %s", e->toChars());
-			}
-			return e;
-		    }
-		}
-	    }
-#endif
-	    e = parsePrimaryExp();
-	    break;
-	}
-	default:
-	    e = parsePrimaryExp();
-	    break;
-    }
-    assert(e);
-    return e;
-}
-
-Expression *Parser::parseMulExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseUnaryExp();
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
-	    case TOKdiv:   nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
-	    case TOKmod:  nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseAddExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseMulExp();
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
-	    case TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
-	    case TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseShiftExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseAddExp();
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
-	    case TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
-	    case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseRelExp()
-{   Expression *e;
-    Expression *e2;
-    enum TOK op;
-    Loc loc = this->loc;
-
-    e = parseShiftExp();
-    while (1)
-    {
-	switch (token.value)
-	{
-	    case TOKlt:
-	    case TOKle:
-	    case TOKgt:
-	    case TOKge:
-	    case TOKunord:
-	    case TOKlg:
-	    case TOKleg:
-	    case TOKule:
-	    case TOKul:
-	    case TOKuge:
-	    case TOKug:
-	    case TOKue:
-		op = token.value;
-		nextToken();
-		e2 = parseShiftExp();
-		e = new CmpExp(op, loc, e, e2);
-		continue;
-
-	    case TOKin:
-		nextToken();
-		e2 = parseShiftExp();
-		e = new InExp(loc, e, e2);
-		continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseEqualExp()
-{   Expression *e;
-    Expression *e2;
-    Token *t;
-    Loc loc = this->loc;
-
-    e = parseRelExp();
-    while (1)
-    {	enum TOK value = token.value;
-
-	switch (value)
-	{
-	    case TOKequal:
-	    case TOKnotequal:
-		nextToken();
-		e2 = parseRelExp();
-		e = new EqualExp(value, loc, e, e2);
-		continue;
-
-	    case TOKidentity:
-		error("'===' is no longer legal, use 'is' instead");
-		goto L1;
-
-	    case TOKnotidentity:
-		error("'!==' is no longer legal, use '!is' instead");
-		goto L1;
-
-	    case TOKis:
-		value = TOKidentity;
-		goto L1;
-
-	    case TOKnot:
-		// Attempt to identify '!is'
-		t = peek(&token);
-		if (t->value != TOKis)
-		    break;
-		nextToken();
-		value = TOKnotidentity;
-		goto L1;
-
-	    L1:
-		nextToken();
-		e2 = parseRelExp();
-		e = new IdentityExp(value, loc, e, e2);
-		continue;
-
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseCmpExp()
-{   Expression *e;
-    Expression *e2;
-    Token *t;
-    Loc loc = this->loc;
-
-    e = parseShiftExp();
-    enum TOK op = token.value;
-
-    switch (op)
-    {
-	case TOKequal:
-	case TOKnotequal:
-	    nextToken();
-	    e2 = parseShiftExp();
-	    e = new EqualExp(op, loc, e, e2);
-	    break;
-
-	case TOKis:
-	    op = TOKidentity;
-	    goto L1;
-
-	case TOKnot:
-	    // Attempt to identify '!is'
-	    t = peek(&token);
-	    if (t->value != TOKis)
-		break;
-	    nextToken();
-	    op = TOKnotidentity;
-	    goto L1;
-
-	L1:
-	    nextToken();
-	    e2 = parseShiftExp();
-	    e = new IdentityExp(op, loc, e, e2);
-	    break;
-
-	case TOKlt:
-	case TOKle:
-	case TOKgt:
-	case TOKge:
-	case TOKunord:
-	case TOKlg:
-	case TOKleg:
-	case TOKule:
-	case TOKul:
-	case TOKuge:
-	case TOKug:
-	case TOKue:
-	    nextToken();
-	    e2 = parseShiftExp();
-	    e = new CmpExp(op, loc, e, e2);
-	    break;
-
-	case TOKin:
-	    nextToken();
-	    e2 = parseShiftExp();
-	    e = new InExp(loc, e, e2);
-	    break;
-
-	default:
-	    break;
-    }
-    return e;
-}
-
-Expression *Parser::parseAndExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    if (global.params.Dversion == 1)
-    {
-	e = parseEqualExp();
-	while (token.value == TOKand)
-	{
-	    nextToken();
-	    e2 = parseEqualExp();
-	    e = new AndExp(loc,e,e2);
-	    loc = this->loc;
-	}
-    }
-    else
-    {
-	e = parseCmpExp();
-	while (token.value == TOKand)
-	{
-	    nextToken();
-	    e2 = parseCmpExp();
-	    e = new AndExp(loc,e,e2);
-	    loc = this->loc;
-	}
-    }
-    return e;
-}
-
-Expression *Parser::parseXorExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseAndExp();
-    while (token.value == TOKxor)
-    {
-	nextToken();
-	e2 = parseAndExp();
-	e = new XorExp(loc, e, e2);
-    }
-    return e;
-}
-
-Expression *Parser::parseOrExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseXorExp();
-    while (token.value == TOKor)
-    {
-	nextToken();
-	e2 = parseXorExp();
-	e = new OrExp(loc, e, e2);
-    }
-    return e;
-}
-
-Expression *Parser::parseAndAndExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseOrExp();
-    while (token.value == TOKandand)
-    {
-	nextToken();
-	e2 = parseOrExp();
-	e = new AndAndExp(loc, e, e2);
-    }
-    return e;
-}
-
-Expression *Parser::parseOrOrExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseAndAndExp();
-    while (token.value == TOKoror)
-    {
-	nextToken();
-	e2 = parseAndAndExp();
-	e = new OrOrExp(loc, e, e2);
-    }
-    return e;
-}
-
-Expression *Parser::parseCondExp()
-{   Expression *e;
-    Expression *e1;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    e = parseOrOrExp();
-    if (token.value == TOKquestion)
-    {
-	nextToken();
-	e1 = parseExpression();
-	check(TOKcolon);
-	e2 = parseCondExp();
-	e = new CondExp(loc, e, e1, e2);
-    }
-    return e;
-}
-
-Expression *Parser::parseAssignExp()
-{   Expression *e;
-    Expression *e2;
-    Loc loc;
-
-    e = parseCondExp();
-    while (1)
-    {
-	loc = this->loc;
-	switch (token.value)
-	{
-#define X(tok,ector) \
-	    case tok:  nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
-
-	    X(TOKassign,    AssignExp);
-	    X(TOKaddass,    AddAssignExp);
-	    X(TOKminass,    MinAssignExp);
-	    X(TOKmulass,    MulAssignExp);
-	    X(TOKdivass,    DivAssignExp);
-	    X(TOKmodass,    ModAssignExp);
-	    X(TOKandass,    AndAssignExp);
-	    X(TOKorass,     OrAssignExp);
-	    X(TOKxorass,    XorAssignExp);
-	    X(TOKshlass,    ShlAssignExp);
-	    X(TOKshrass,    ShrAssignExp);
-	    X(TOKushrass,   UshrAssignExp);
-	    X(TOKcatass,    CatAssignExp);
-
-#undef X
-	    default:
-		break;
-	}
-	break;
-    }
-    return e;
-}
-
-Expression *Parser::parseExpression()
-{   Expression *e;
-    Expression *e2;
-    Loc loc = this->loc;
-
-    //printf("Parser::parseExpression()\n");
-    e = parseAssignExp();
-    while (token.value == TOKcomma)
-    {
-	nextToken();
-	e2 = parseAssignExp();
-	e = new CommaExp(loc, e, e2);
-	loc = this->loc;
-    }
-    return e;
-}
-
-
-/*************************
- * Collect argument list.
- * Assume current token is '(' or '['.
- */
-
-Expressions *Parser::parseArguments()
-{   // function call
-    Expressions *arguments;
-    Expression *arg;
-    enum TOK endtok;
-
-    arguments = new Expressions();
-    if (token.value == TOKlbracket)
-	endtok = TOKrbracket;
-    else
-	endtok = TOKrparen;
-
-    {
-	nextToken();
-	if (token.value != endtok)
-	{
-	    while (1)
-	    {
-		arg = parseAssignExp();
-		arguments->push(arg);
-		if (token.value == endtok)
-		    break;
-		check(TOKcomma);
-	    }
-	}
-	check(endtok);
-    }
-    return arguments;
-}
-
-/*******************************************
- */
-
-Expression *Parser::parseNewExp(Expression *thisexp)
-{   Type *t;
-    Expressions *newargs;
-    Expressions *arguments = NULL;
-    Expression *e;
-    Loc loc = this->loc;
-
-    nextToken();
-    newargs = NULL;
-    if (token.value == TOKlparen)
-    {
-	newargs = parseArguments();
-    }
-
-    // An anonymous nested class starts with "class"
-    if (token.value == TOKclass)
-    {
-	nextToken();
-	if (token.value == TOKlparen)
-	    arguments = parseArguments();
-
-	BaseClasses *baseclasses = NULL;
-	if (token.value != TOKlcurly)
-	    baseclasses = parseBaseClasses();
-
-	Identifier *id = NULL;
-	ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
-
-	if (token.value != TOKlcurly)
-	{   error("{ members } expected for anonymous class");
-	    cd->members = NULL;
-	}
-	else
-	{
-	    nextToken();
-	    Array *decl = parseDeclDefs(0);
-	    if (token.value != TOKrcurly)
-		error("class member expected");
-	    nextToken();
-	    cd->members = decl;
-	}
-
-	e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
-
-	return e;
-    }
-
-#if LTORARRAYDECL
-    t = parseBasicType();
-    t = parseBasicType2(t);
-    if (t->ty == Taarray)
-    {
-	Type *index = ((TypeAArray *)t)->index;
-
-	Expression *e = index->toExpression();
-	if (e)
-	{   arguments = new Expressions();
-	    arguments->push(e);
-	    t = new TypeDArray(t->next);
-	}
-	else
-	{
-	    error("need size of rightmost array, not type %s", index->toChars());
-	    return new NullExp(loc);
-	}
-    }
-    else if (t->ty == Tsarray)
-    {
-	TypeSArray *tsa = (TypeSArray *)t;
-	Expression *e = tsa->dim;
-
-	arguments = new Expressions();
-	arguments->push(e);
-	t = new TypeDArray(t->next);
-    }
-    else if (token.value == TOKlparen)
-    {
-	arguments = parseArguments();
-    }
-#else
-    t = parseBasicType();
-    while (token.value == TOKmul)
-    {   t = new TypePointer(t);
-	nextToken();
-    }
-    if (token.value == TOKlbracket)
-    {
-	Expression *e;
-
-	nextToken();
-	e = parseAssignExp();
-	arguments = new Array();
-	arguments->push(e);
-	check(TOKrbracket);
-	t = parseDeclarator(t, NULL);
-	t = new TypeDArray(t);
-    }
-    else if (token.value == TOKlparen)
-	arguments = parseArguments();
-#endif
-    e = new NewExp(loc, thisexp, newargs, t, arguments);
-    return e;
-}
-
-/**********************************************
- */
-
-void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
-{
-    s->addComment(combineComments(blockComment, token.lineComment));
-}
-
-
-/********************************* ***************************/
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// This is the D parser
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mem.h"
+#include "lexer.h"
+#include "parse.h"
+#include "init.h"
+#include "attrib.h"
+#include "cond.h"
+#include "mtype.h"
+#include "template.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "statement.h"
+#include "module.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "enum.h"
+#include "id.h"
+#include "version.h"
+
+// How multiple declarations are parsed.
+// If 1, treat as C.
+// If 0, treat:
+//	int *p, i;
+// as:
+//	int* p;
+//	int* i;
+#define CDECLSYNTAX	0
+
+// Support C cast syntax:
+//	(type)(expression)
+#define CCASTSYNTAX	1
+
+// Support postfix C array declarations, such as
+//	int a[3][4];
+#define CARRAYDECL	1
+
+// Support left-to-right array declarations
+#define LTORARRAYDECL	1
+
+
+Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
+    : Lexer(module, base, 0, length, doDocComment, 0)
+{
+    //printf("Parser::Parser()\n");
+    md = NULL;
+    linkage = LINKd;
+    endloc = 0;
+    inBrackets = 0;
+    //nextToken();		// start up the scanner
+}
+
+Array *Parser::parseModule()
+{
+    Array *decldefs;
+
+    // ModuleDeclation leads off
+    if (token.value == TOKmodule)
+    {
+	unsigned char *comment = token.blockComment;
+
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("Identifier expected following module");
+	    goto Lerr;
+	}
+	else
+	{
+	    Array *a = NULL;
+	    Identifier *id;
+
+	    id = token.ident;
+	    while (nextToken() == TOKdot)
+	    {
+		if (!a)
+		    a = new Array();
+		a->push(id);
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following package");
+		    goto Lerr;
+		}
+		id = token.ident;
+	    }
+
+	    md = new ModuleDeclaration(a, id);
+
+	    if (token.value != TOKsemicolon)
+		error("';' expected following module declaration instead of %s", token.toChars());
+	    nextToken();
+	    addComment(mod, comment);
+	}
+    }
+
+    decldefs = parseDeclDefs(0);
+    if (token.value != TOKeof)
+    {	error("unrecognized declaration");
+	goto Lerr;
+    }
+    return decldefs;
+
+Lerr:
+    while (token.value != TOKsemicolon && token.value != TOKeof)
+	nextToken();
+    nextToken();
+    return new Array();
+}
+
+Array *Parser::parseDeclDefs(int once)
+{   Dsymbol *s;
+    Array *decldefs;
+    Array *a;
+    Array *aelse;
+    enum PROT prot;
+    unsigned stc;
+    Condition *condition;
+    unsigned char *comment;
+
+    //printf("Parser::parseDeclDefs()\n");
+    decldefs = new Array();
+    do
+    {
+	comment = token.blockComment;
+	switch (token.value)
+	{
+	    case TOKenum:
+		s = parseEnum();
+		break;
+
+	    case TOKstruct:
+	    case TOKunion:
+	    case TOKclass:
+	    case TOKinterface:
+		s = parseAggregate();
+		break;
+
+	    case TOKimport:
+		s = parseImport(decldefs, 0);
+		break;
+
+	    case TOKtemplate:
+		s = (Dsymbol *)parseTemplateDeclaration();
+		break;
+
+	    case TOKmixin:
+	    {	Loc loc = this->loc;
+		if (peek(&token)->value == TOKlparen)
+		{   // mixin(string)
+		    nextToken();
+		    check(TOKlparen, "mixin");
+		    Expression *e = parseAssignExp();
+		    check(TOKrparen);
+		    check(TOKsemicolon);
+		    s = new CompileDeclaration(loc, e);
+		    break;
+		}
+		s = parseMixin();
+		break;
+	    }
+
+	    CASE_BASIC_TYPES:
+	    case TOKalias:
+	    case TOKtypedef:
+	    case TOKidentifier:
+	    case TOKtypeof:
+	    case TOKdot:
+	    Ldeclaration:
+		a = parseDeclarations();
+		decldefs->append(a);
+		continue;
+
+	    case TOKthis:
+		s = parseCtor();
+		break;
+
+	    case TOKtilde:
+		s = parseDtor();
+		break;
+
+	    case TOKinvariant:
+#if 1
+		s = parseInvariant();
+#else
+		if (peek(&token)->value == TOKlcurly)
+		    s = parseInvariant();
+		else
+		{
+		    stc = STCinvariant;
+		    goto Lstc;
+		}
+#endif
+		break;
+
+	    case TOKunittest:
+		s = parseUnitTest();
+		break;
+
+	    case TOKnew:
+		s = parseNew();
+		break;
+
+	    case TOKdelete:
+		s = parseDelete();
+		break;
+
+	    case TOKeof:
+	    case TOKrcurly:
+		return decldefs;
+
+	    case TOKstatic:
+		nextToken();
+		if (token.value == TOKthis)
+		    s = parseStaticCtor();
+		else if (token.value == TOKtilde)
+		    s = parseStaticDtor();
+		else if (token.value == TOKassert)
+		    s = parseStaticAssert();
+		else if (token.value == TOKif)
+		{   condition = parseStaticIfCondition();
+		    a = parseBlock();
+		    aelse = NULL;
+		    if (token.value == TOKelse)
+		    {   nextToken();
+			aelse = parseBlock();
+		    }
+		    s = new StaticIfDeclaration(condition, a, aelse);
+		    break;
+		}
+		else if (token.value == TOKimport)
+		{
+		    s = parseImport(decldefs, 1);
+		}
+		else
+		{   stc = STCstatic;
+		    goto Lstc2;
+		}
+		break;
+
+	    case TOKconst:	  stc = STCconst;	 goto Lstc;
+	    case TOKfinal:	  stc = STCfinal;	 goto Lstc;
+	    case TOKauto:	  stc = STCauto;	 goto Lstc;
+	    case TOKscope:	  stc = STCscope;	 goto Lstc;
+	    case TOKoverride:	  stc = STCoverride;	 goto Lstc;
+	    case TOKabstract:	  stc = STCabstract;	 goto Lstc;
+	    case TOKsynchronized: stc = STCsynchronized; goto Lstc;
+	    case TOKdeprecated:   stc = STCdeprecated;	 goto Lstc;
+
+	    Lstc:
+		nextToken();
+	    Lstc2:
+		switch (token.value)
+		{
+		    case TOKconst:	  stc |= STCconst;	 goto Lstc;
+		    case TOKfinal:	  stc |= STCfinal;	 goto Lstc;
+		    case TOKauto:	  stc |= STCauto;	 goto Lstc;
+		    case TOKscope:	  stc |= STCscope;	 goto Lstc;
+		    case TOKoverride:	  stc |= STCoverride;	 goto Lstc;
+		    case TOKabstract:	  stc |= STCabstract;	 goto Lstc;
+		    case TOKsynchronized: stc |= STCsynchronized; goto Lstc;
+		    case TOKdeprecated:   stc |= STCdeprecated;	 goto Lstc;
+		    //case TOKinvariant:    stc |= STCinvariant;   goto Lstc;
+		    default:
+			break;
+		}
+
+		/* Look for auto initializers:
+		 *	storage_class identifier = initializer;
+		 */
+		if (token.value == TOKidentifier &&
+		    peek(&token)->value == TOKassign)
+		{
+		    while (1)
+		    {
+			Identifier *ident = token.ident;
+			nextToken();
+			nextToken();
+			Initializer *init = parseInitializer();
+			VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+			v->storage_class = stc;
+			s = v;
+			if (token.value == TOKsemicolon)
+			{
+			    nextToken();
+			}
+			else if (token.value == TOKcomma)
+			{
+			    nextToken();
+			    if (token.value == TOKidentifier &&
+				peek(&token)->value == TOKassign)
+			    {
+				decldefs->push(s);
+				addComment(s, comment);
+				continue;
+			    }
+			    else
+				error("Identifier expected following comma");
+			}
+			else
+			    error("semicolon expected following auto declaration, not '%s'", token.toChars());
+			break;
+		    }
+		}
+		else
+		{   a = parseBlock();
+		    s = new StorageClassDeclaration(stc, a);
+		}
+		break;
+
+	    case TOKextern:
+		if (peek(&token)->value != TOKlparen)
+		{   stc = STCextern;
+		    goto Lstc;
+		}
+	    {
+		enum LINK linksave = linkage;
+		linkage = parseLinkage();
+		a = parseBlock();
+		s = new LinkDeclaration(linkage, a);
+		linkage = linksave;
+		break;
+	    }
+	    case TOKprivate:	prot = PROTprivate;	goto Lprot;
+	    case TOKpackage:	prot = PROTpackage;	goto Lprot;
+	    case TOKprotected:	prot = PROTprotected;	goto Lprot;
+	    case TOKpublic:	prot = PROTpublic;	goto Lprot;
+	    case TOKexport:	prot = PROTexport;	goto Lprot;
+
+	    Lprot:
+		nextToken();
+		a = parseBlock();
+		s = new ProtDeclaration(prot, a);
+		break;
+
+	    case TOKalign:
+	    {	unsigned n;
+
+		s = NULL;
+		nextToken();
+		if (token.value == TOKlparen)
+		{
+		    nextToken();
+		    if (token.value == TOKint32v)
+			n = (unsigned)token.uns64value;
+		    else
+		    {	error("integer expected, not %s", token.toChars());
+			n = 1;
+		    }
+		    nextToken();
+		    check(TOKrparen);
+		}
+		else
+		    n = global.structalign;		// default
+
+		a = parseBlock();
+		s = new AlignDeclaration(n, a);
+		break;
+	    }
+
+	    case TOKpragma:
+	    {	Identifier *ident;
+		Expressions *args = NULL;
+
+		nextToken();
+		check(TOKlparen);
+		if (token.value != TOKidentifier)
+		{   error("pragma(identifier expected");
+		    goto Lerror;
+		}
+		ident = token.ident;
+		nextToken();
+		if (token.value == TOKcomma)
+		    args = parseArguments();	// pragma(identifier, args...)
+		else
+		    check(TOKrparen);		// pragma(identifier)
+
+		if (token.value == TOKsemicolon)
+		    a = NULL;
+		else
+		    a = parseBlock();
+		s = new PragmaDeclaration(loc, ident, args, a);
+		break;
+	    }
+
+	    case TOKdebug:
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+			s = new DebugSymbol(loc, token.ident);
+		    else if (token.value == TOKint32v)
+			s = new DebugSymbol(loc, (unsigned)token.uns64value);
+		    else
+		    {	error("identifier or integer expected, not %s", token.toChars());
+			s = NULL;
+		    }
+		    nextToken();
+		    if (token.value != TOKsemicolon)
+			error("semicolon expected");
+		    nextToken();
+		    break;
+		}
+
+		condition = parseDebugCondition();
+		goto Lcondition;
+
+	    case TOKversion:
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+			s = new VersionSymbol(loc, token.ident);
+		    else if (token.value == TOKint32v)
+			s = new VersionSymbol(loc, (unsigned)token.uns64value);
+		    else
+		    {	error("identifier or integer expected, not %s", token.toChars());
+			s = NULL;
+		    }
+		    nextToken();
+		    if (token.value != TOKsemicolon)
+			error("semicolon expected");
+		    nextToken();
+		    break;
+		}
+		condition = parseVersionCondition();
+		goto Lcondition;
+
+	    Lcondition:
+		a = parseBlock();
+		aelse = NULL;
+		if (token.value == TOKelse)
+		{   nextToken();
+		    aelse = parseBlock();
+		}
+		s = new ConditionalDeclaration(condition, a, aelse);
+		break;
+
+	    case TOKsemicolon:		// empty declaration
+		nextToken();
+		continue;
+
+	    default:
+		error("Declaration expected, not '%s'",token.toChars());
+	    Lerror:
+		while (token.value != TOKsemicolon && token.value != TOKeof)
+		    nextToken();
+		nextToken();
+		s = NULL;
+		continue;
+	}
+	if (s)
+	{   decldefs->push(s);
+	    addComment(s, comment);
+	}
+    } while (!once);
+    return decldefs;
+}
+
+
+/********************************************
+ * Parse declarations after an align, protection, or extern decl.
+ */
+
+Array *Parser::parseBlock()
+{
+    Array *a = NULL;
+    Dsymbol *s;
+
+    //printf("parseBlock()\n");
+    switch (token.value)
+    {
+	case TOKsemicolon:
+	    error("declaration expected following attribute, not ';'");
+	    nextToken();
+	    break;
+
+	case TOKlcurly:
+	    nextToken();
+	    a = parseDeclDefs(0);
+	    if (token.value != TOKrcurly)
+	    {   /* { */
+		error("matching '}' expected, not %s", token.toChars());
+	    }
+	    else
+		nextToken();
+	    break;
+
+	case TOKcolon:
+	    nextToken();
+#if 0
+	    a = NULL;
+#else
+	    a = parseDeclDefs(0);	// grab declarations up to closing curly bracket
+#endif
+	    break;
+
+	default:
+	    a = parseDeclDefs(1);
+	    break;
+    }
+    return a;
+}
+
+/**********************************
+ * Parse a static assertion.
+ */
+
+StaticAssert *Parser::parseStaticAssert()
+{
+    Loc loc = this->loc;
+    Expression *exp;
+    Expression *msg = NULL;
+
+    //printf("parseStaticAssert()\n");
+    nextToken();
+    check(TOKlparen);
+    exp = parseAssignExp();
+    if (token.value == TOKcomma)
+    {	nextToken();
+	msg = parseAssignExp();
+    }
+    check(TOKrparen);
+    check(TOKsemicolon);
+    return new StaticAssert(loc, exp, msg);
+}
+
+/***********************************
+ * Parse typeof(expression).
+ * Current token is on the 'typeof'.
+ */
+
+#if DMDV2
+TypeQualified *Parser::parseTypeof()
+{   TypeQualified *t;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKlparen);
+    if (token.value == TOKreturn)	// typeof(return)
+    {
+	nextToken();
+	t = new TypeReturn(loc);
+    }
+    else
+    {	Expression *exp = parseExpression();	// typeof(expression)
+	t = new TypeTypeof(loc, exp);
+    }
+    check(TOKrparen);
+    return t;
+}
+#endif
+
+/***********************************
+ * Parse extern (linkage)
+ * The parser is on the 'extern' token.
+ */
+
+enum LINK Parser::parseLinkage()
+{
+    enum LINK link = LINKdefault;
+    nextToken();
+    assert(token.value == TOKlparen);
+    nextToken();
+    if (token.value == TOKidentifier)
+    {   Identifier *id = token.ident;
+
+	nextToken();
+	if (id == Id::Windows)
+	    link = LINKwindows;
+	else if (id == Id::Pascal)
+	    link = LINKpascal;
+	else if (id == Id::D)
+	    link = LINKd;
+	else if (id == Id::C)
+	{
+	    link = LINKc;
+	    if (token.value == TOKplusplus)
+	    {   link = LINKcpp;
+		nextToken();
+	    }
+	}
+	else if (id == Id::System)
+	{
+#if _WIN32
+	    link = LINKwindows;
+#else
+	    link = LINKc;
+#endif
+	}
+	else
+	{
+	    error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
+	    link = LINKd;
+	}
+    }
+    else
+    {
+	link = LINKd;		// default
+    }
+    check(TOKrparen);
+    return link;
+}
+
+/**************************************
+ * Parse a debug conditional
+ */
+
+Condition *Parser::parseDebugCondition()
+{
+    Condition *c;
+
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	unsigned level = 1;
+	Identifier *id = NULL;
+
+	if (token.value == TOKidentifier)
+	    id = token.ident;
+	else if (token.value == TOKint32v)
+	    level = (unsigned)token.uns64value;
+	else
+	    error("identifier or integer expected, not %s", token.toChars());
+	nextToken();
+	check(TOKrparen);
+	c = new DebugCondition(mod, level, id);
+    }
+    else
+	c = new DebugCondition(mod, 1, NULL);
+    return c;
+
+}
+
+/**************************************
+ * Parse a version conditional
+ */
+
+Condition *Parser::parseVersionCondition()
+{
+    Condition *c;
+    unsigned level = 1;
+    Identifier *id = NULL;
+
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	if (token.value == TOKidentifier)
+	    id = token.ident;
+	else if (token.value == TOKint32v)
+	    level = (unsigned)token.uns64value;
+#if DMDV2
+	/* Allow:
+	 *    version (unittest)
+	 * even though unittest is a keyword
+	 */
+	else if (token.value == TOKunittest)
+	    id = Lexer::idPool(Token::toChars(TOKunittest));
+#endif
+	else
+	    error("identifier or integer expected, not %s", token.toChars());
+	nextToken();
+	check(TOKrparen);
+
+    }
+    else
+       error("(condition) expected following version");
+    c = new VersionCondition(mod, level, id);
+    return c;
+
+}
+
+/***********************************************
+ *	static if (expression)
+ *	    body
+ *	else
+ *	    body
+ */
+
+Condition *Parser::parseStaticIfCondition()
+{   Expression *exp;
+    Condition *condition;
+    Array *aif;
+    Array *aelse;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	exp = parseAssignExp();
+	check(TOKrparen);
+    }
+    else
+    {   error("(expression) expected following static if");
+	exp = NULL;
+    }
+    condition = new StaticIfCondition(loc, exp);
+    return condition;
+}
+
+
+/*****************************************
+ * Parse a constructor definition:
+ *	this(arguments) { body }
+ * Current token is 'this'.
+ */
+
+CtorDeclaration *Parser::parseCtor()
+{
+    CtorDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    f = new CtorDeclaration(loc, 0, arguments, varargs);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a destructor definition:
+ *	~this() { body }
+ * Current token is '~'.
+ */
+
+DtorDeclaration *Parser::parseDtor()
+{
+    DtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new DtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a static constructor definition:
+ *	static this() { body }
+ * Current token is 'this'.
+ */
+
+StaticCtorDeclaration *Parser::parseStaticCtor()
+{
+    StaticCtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new StaticCtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a static destructor definition:
+ *	static ~this() { body }
+ * Current token is '~'.
+ */
+
+StaticDtorDeclaration *Parser::parseStaticDtor()
+{
+    StaticDtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new StaticDtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse an invariant definition:
+ *	invariant { body }
+ * Current token is 'invariant'.
+ */
+
+InvariantDeclaration *Parser::parseInvariant()
+{
+    InvariantDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value == TOKlparen)	// optional ()
+    {
+	nextToken();
+	check(TOKrparen);
+    }
+
+    f = new InvariantDeclaration(loc, 0);
+    f->fbody = parseStatement(PScurly);
+    return f;
+}
+
+/*****************************************
+ * Parse a unittest definition:
+ *	unittest { body }
+ * Current token is 'unittest'.
+ */
+
+UnitTestDeclaration *Parser::parseUnitTest()
+{
+    UnitTestDeclaration *f;
+    Statement *body;
+    Loc loc = this->loc;
+
+    nextToken();
+
+    body = parseStatement(PScurly);
+
+    f = new UnitTestDeclaration(loc, this->loc);
+    f->fbody = body;
+    return f;
+}
+
+/*****************************************
+ * Parse a new definition:
+ *	new(arguments) { body }
+ * Current token is 'new'.
+ */
+
+NewDeclaration *Parser::parseNew()
+{
+    NewDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    f = new NewDeclaration(loc, 0, arguments, varargs);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a delete definition:
+ *	delete(arguments) { body }
+ * Current token is 'delete'.
+ */
+
+DeleteDeclaration *Parser::parseDelete()
+{
+    DeleteDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    if (varargs)
+	error("... not allowed in delete function parameter list");
+    f = new DeleteDeclaration(loc, 0, arguments);
+    parseContracts(f);
+    return f;
+}
+
+/**********************************************
+ * Parse parameter list.
+ */
+
+Arguments *Parser::parseParameters(int *pvarargs)
+{
+    Arguments *arguments = new Arguments();
+    int varargs = 0;
+    int hasdefault = 0;
+
+    check(TOKlparen);
+    while (1)
+    {   Type *tb;
+	Identifier *ai = NULL;
+	Type *at;
+	Argument *a;
+	unsigned storageClass;
+	Expression *ae;
+
+	storageClass = STCin;		// parameter is "in" by default
+	switch (token.value)
+	{
+	    case TOKrparen:
+		break;
+
+	    case TOKdotdotdot:
+		varargs = 1;
+		nextToken();
+		break;
+
+	    case TOKin:
+		storageClass = STCin;
+		nextToken();
+		goto L1;
+
+	    case TOKout:
+		storageClass = STCout;
+		nextToken();
+		goto L1;
+
+	    case TOKinout:
+	    case TOKref:
+		storageClass = STCref;
+		nextToken();
+		goto L1;
+
+	    case TOKlazy:
+		storageClass = STClazy;
+		nextToken();
+		goto L1;
+
+	    default:
+	    L1:
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		ae = NULL;
+		if (token.value == TOKassign)	// = defaultArg
+		{   nextToken();
+		    ae = parseAssignExp();
+		    hasdefault = 1;
+		}
+		else
+		{   if (hasdefault)
+			error("default argument expected for %s",
+				ai ? ai->toChars() : at->toChars());
+		}
+		if (token.value == TOKdotdotdot)
+		{   /* This is:
+		     *	at ai ...
+		     */
+
+		    if (storageClass & (STCout | STCref))
+			error("variadic argument cannot be out or ref");
+		    varargs = 2;
+		    a = new Argument(storageClass, at, ai, ae);
+		    arguments->push(a);
+		    nextToken();
+		    break;
+		}
+		a = new Argument(storageClass, at, ai, ae);
+		arguments->push(a);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	}
+	break;
+    }
+    check(TOKrparen);
+    *pvarargs = varargs;
+    return arguments;
+}
+
+
+/*************************************
+ */
+
+EnumDeclaration *Parser::parseEnum()
+{   EnumDeclaration *e;
+    Identifier *id;
+    Type *t;
+    Loc loc = this->loc;
+
+    //printf("Parser::parseEnum()\n");
+    nextToken();
+    if (token.value == TOKidentifier)
+    {	id = token.ident;
+	nextToken();
+    }
+    else
+	id = NULL;
+
+    if (token.value == TOKcolon)
+    {
+	nextToken();
+	t = parseBasicType();
+    }
+    else
+	t = NULL;
+
+    e = new EnumDeclaration(loc, id, t);
+    if (token.value == TOKsemicolon && id)
+ 	nextToken();
+    else if (token.value == TOKlcurly)
+    {
+	//printf("enum definition\n");
+	e->members = new Array();
+	nextToken();
+	unsigned char *comment = token.blockComment;
+	while (token.value != TOKrcurly)
+	{
+	    if (token.value == TOKidentifier)
+	    {	EnumMember *em;
+		Expression *value;
+		Identifier *ident;
+
+		loc = this->loc;
+		ident = token.ident;
+		value = NULL;
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    value = parseAssignExp();
+		}
+		em = new EnumMember(loc, ident, value);
+		e->members->push(em);
+		if (token.value == TOKrcurly)
+		    ;
+		else
+		{   addComment(em, comment);
+		    comment = NULL;
+		    check(TOKcomma);
+		}
+		addComment(em, comment);
+		comment = token.blockComment;
+	    }
+	    else
+	    {	error("enum member expected");
+		nextToken();
+	    }
+	}
+	nextToken();
+    }
+    else
+	error("enum declaration is invalid");
+
+    //printf("-parseEnum() %s\n", e->toChars());
+    return e;
+}
+
+Dsymbol *Parser::parseAggregate()
+{   AggregateDeclaration *a = NULL;
+    int anon = 0;
+    enum TOK tok;
+    Identifier *id;
+    TemplateParameters *tpl = NULL;
+
+    //printf("Parser::parseAggregate()\n");
+    tok = token.value;
+    nextToken();
+    if (token.value != TOKidentifier)
+    {	id = NULL;
+    }
+    else
+    {	id = token.ident;
+	nextToken();
+
+	if (token.value == TOKlparen)
+	{   // Class template declaration.
+
+	    // Gather template parameter list
+	    tpl = parseTemplateParameterList();
+	}
+    }
+
+    Loc loc = this->loc;
+    switch (tok)
+    {	case TOKclass:
+	case TOKinterface:
+	{
+	    if (!id)
+		error("anonymous classes not allowed");
+
+	    // Collect base class(es)
+	    BaseClasses *baseclasses = NULL;
+	    if (token.value == TOKcolon)
+	    {
+		nextToken();
+		baseclasses = parseBaseClasses();
+
+		if (token.value != TOKlcurly)
+		    error("members expected");
+	    }
+
+	    if (tok == TOKclass)
+		a = new ClassDeclaration(loc, id, baseclasses);
+	    else
+		a = new InterfaceDeclaration(loc, id, baseclasses);
+	    break;
+	}
+
+	case TOKstruct:
+	    if (id)
+		a = new StructDeclaration(loc, id);
+	    else
+		anon = 1;
+	    break;
+
+	case TOKunion:
+	    if (id)
+		a = new UnionDeclaration(loc, id);
+	    else
+		anon = 2;
+	    break;
+
+	default:
+	    assert(0);
+	    break;
+    }
+    if (a && token.value == TOKsemicolon)
+    { 	nextToken();
+    }
+    else if (token.value == TOKlcurly)
+    {
+	//printf("aggregate definition\n");
+	nextToken();
+	Array *decl = parseDeclDefs(0);
+	if (token.value != TOKrcurly)
+	    error("} expected following member declarations in aggregate");
+	nextToken();
+	if (anon)
+	{
+	    /* Anonymous structs/unions are more like attributes.
+	     */
+	    return new AnonDeclaration(loc, anon - 1, decl);
+	}
+	else
+	    a->members = decl;
+    }
+    else
+    {
+	error("{ } expected following aggregate declaration");
+	a = new StructDeclaration(loc, NULL);
+    }
+
+    if (tpl)
+    {	Array *decldefs;
+	TemplateDeclaration *tempdecl;
+
+	// Wrap a template around the aggregate declaration
+	decldefs = new Array();
+	decldefs->push(a);
+	tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
+	return tempdecl;
+    }
+
+    return a;
+}
+
+/*******************************************
+ */
+
+BaseClasses *Parser::parseBaseClasses()
+{
+    enum PROT protection = PROTpublic;
+    BaseClasses *baseclasses = new BaseClasses();
+
+    for (; 1; nextToken())
+    {
+	switch (token.value)
+	{
+	    case TOKidentifier:
+		break;
+	    case TOKprivate:
+		protection = PROTprivate;
+		continue;
+	    case TOKpackage:
+		protection = PROTpackage;
+		continue;
+	    case TOKprotected:
+		protection = PROTprotected;
+		continue;
+	    case TOKpublic:
+		protection = PROTpublic;
+		continue;
+	    default:
+		error("base classes expected instead of %s", token.toChars());
+		return NULL;
+	}
+	BaseClass *b = new BaseClass(parseBasicType(), protection);
+	baseclasses->push(b);
+	if (token.value != TOKcomma)
+	    break;
+	protection = PROTpublic;
+    }
+    return baseclasses;
+}
+
+/**************************************
+ * Parse constraint.
+ * Constraint is of the form:
+ *	if ( ConstraintExpression )
+ */
+
+#if DMDV2
+Expression *Parser::parseConstraint()
+{   Expression *e = NULL;
+
+    if (token.value == TOKif)
+    {
+	nextToken();	// skip over 'if'
+	check(TOKlparen);
+	e = parseExpression();
+	check(TOKrparen);
+    }
+    return e;
+}
+#endif
+
+/**************************************
+ * Parse a TemplateDeclaration.
+ */
+
+TemplateDeclaration *Parser::parseTemplateDeclaration()
+{
+    TemplateDeclaration *tempdecl;
+    Identifier *id;
+    TemplateParameters *tpl;
+    Array *decldefs;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value != TOKidentifier)
+    {   error("TemplateIdentifier expected following template");
+	goto Lerr;
+    }
+    id = token.ident;
+    nextToken();
+    tpl = parseTemplateParameterList();
+    if (!tpl)
+	goto Lerr;
+
+    if (token.value != TOKlcurly)
+    {	error("members of template declaration expected");
+	goto Lerr;
+    }
+    else
+    {
+	nextToken();
+	decldefs = parseDeclDefs(0);
+	if (token.value != TOKrcurly)
+	{   error("template member expected");
+	    goto Lerr;
+	}
+	nextToken();
+    }
+
+    tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
+    return tempdecl;
+
+Lerr:
+    return NULL;
+}
+
+/******************************************
+ * Parse template parameter list.
+ */
+
+TemplateParameters *Parser::parseTemplateParameterList()
+{
+    TemplateParameters *tpl = new TemplateParameters();
+
+    if (token.value != TOKlparen)
+    {   error("parenthesized TemplateParameterList expected following TemplateIdentifier");
+	goto Lerr;
+    }
+    nextToken();
+
+    // Get array of TemplateParameters
+    if (token.value != TOKrparen)
+    {	int isvariadic = 0;
+
+	while (1)
+	{   TemplateParameter *tp;
+	    Identifier *tp_ident = NULL;
+	    Type *tp_spectype = NULL;
+	    Type *tp_valtype = NULL;
+	    Type *tp_defaulttype = NULL;
+	    Expression *tp_specvalue = NULL;
+	    Expression *tp_defaultvalue = NULL;
+	    Token *t;
+
+	    // Get TemplateParameter
+
+	    // First, look ahead to see if it is a TypeParameter or a ValueParameter
+	    t = peek(&token);
+	    if (token.value == TOKalias)
+	    {	// AliasParameter
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected for template parameter");
+		    goto Lerr;
+		}
+		tp_ident = token.ident;
+		nextToken();
+		if (token.value == TOKcolon)	// : Type
+		{
+		    nextToken();
+		    tp_spectype = parseBasicType();
+		    tp_spectype = parseDeclarator(tp_spectype, NULL);
+		}
+		if (token.value == TOKassign)	// = Type
+		{
+		    nextToken();
+		    tp_defaulttype = parseBasicType();
+		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
+		}
+		tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+	    }
+	    else if (t->value == TOKcolon || t->value == TOKassign ||
+		     t->value == TOKcomma || t->value == TOKrparen)
+	    {	// TypeParameter
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected for template parameter");
+		    goto Lerr;
+		}
+		tp_ident = token.ident;
+		nextToken();
+		if (token.value == TOKcolon)	// : Type
+		{
+		    nextToken();
+		    tp_spectype = parseBasicType();
+		    tp_spectype = parseDeclarator(tp_spectype, NULL);
+		}
+		if (token.value == TOKassign)	// = Type
+		{
+		    nextToken();
+		    tp_defaulttype = parseBasicType();
+		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
+		}
+		tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+	    }
+	    else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
+	    {	// ident...
+		if (isvariadic)
+		    error("variadic template parameter must be last");
+		isvariadic = 1;
+		tp_ident = token.ident;
+		nextToken();
+		nextToken();
+		tp = new TemplateTupleParameter(loc, tp_ident);
+	    }
+#if DMDV2
+	    else if (token.value == TOKthis)
+	    {	// ThisParameter
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("identifier expected for template this parameter");
+		    goto Lerr;
+		}
+		tp_ident = token.ident;
+		nextToken();
+		if (token.value == TOKcolon)	// : Type
+		{
+		    nextToken();
+		    tp_spectype = parseType();
+		}
+		if (token.value == TOKassign)	// = Type
+		{
+		    nextToken();
+		    tp_defaulttype = parseType();
+		}
+		tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+	    }
+#endif
+	    else
+	    {	// ValueParameter
+		tp_valtype = parseBasicType();
+		tp_valtype = parseDeclarator(tp_valtype, &tp_ident);
+		if (!tp_ident)
+		{
+		    error("identifier expected for template value parameter");
+		    tp_ident = new Identifier("error", TOKidentifier);
+		}
+		if (token.value == TOKcolon)	// : CondExpression
+		{
+		    nextToken();
+		    tp_specvalue = parseCondExp();
+		}
+		if (token.value == TOKassign)	// = CondExpression
+		{
+		    nextToken();
+		    tp_defaultvalue = parseCondExp();
+		}
+		tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+	    }
+	    tpl->push(tp);
+	    if (token.value != TOKcomma)
+		break;
+	    nextToken();
+	}
+    }
+    check(TOKrparen);
+Lerr:
+    return tpl;
+}
+
+/******************************************
+ * Parse template mixin.
+ *	mixin Foo;
+ *	mixin Foo!(args);
+ *	mixin a.b.c!(args).Foo!(args);
+ *	mixin Foo!(args) identifier;
+ *	mixin typeof(expr).identifier!(args);
+ */
+
+Dsymbol *Parser::parseMixin()
+{
+    TemplateMixin *tm;
+    Identifier *id;
+    Type *tqual;
+    Objects *tiargs;
+    Array *idents;
+
+    //printf("parseMixin()\n");
+    nextToken();
+    tqual = NULL;
+    if (token.value == TOKdot)
+    {
+	id = Id::empty;
+    }
+    else
+    {
+	if (token.value == TOKtypeof)
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    tqual = new TypeTypeof(loc, exp);
+	    check(TOKdot);
+	}
+	if (token.value != TOKidentifier)
+	{
+	    error("identifier expected, not %s", token.toChars());
+	    id = Id::empty;
+	}
+	else
+	    id = token.ident;
+	nextToken();
+    }
+
+    idents = new Array();
+    while (1)
+    {
+	tiargs = NULL;
+	if (token.value == TOKnot)
+	{
+	    nextToken();
+	    tiargs = parseTemplateArgumentList();
+	}
+
+	if (token.value != TOKdot)
+	    break;
+
+	if (tiargs)
+	{   TemplateInstance *tempinst = new TemplateInstance(loc, id);
+	    tempinst->tiargs = tiargs;
+	    id = (Identifier *)tempinst;
+	    tiargs = NULL;
+	}
+	idents->push(id);
+
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("identifier expected following '.' instead of '%s'", token.toChars());
+	    break;
+	}
+	id = token.ident;
+	nextToken();
+    }
+    idents->push(id);
+
+    if (token.value == TOKidentifier)
+    {
+	id = token.ident;
+	nextToken();
+    }
+    else
+	id = NULL;
+
+    tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
+    if (token.value != TOKsemicolon)
+	error("';' expected after mixin");
+    nextToken();
+
+    return tm;
+}
+
+/******************************************
+ * Parse template argument list.
+ * Input:
+ * 	current token is opening '('
+ * Output:
+ *	current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArgumentList()
+{
+    //printf("Parser::parseTemplateArgumentList()\n");
+    Objects *tiargs = new Objects();
+    if (token.value != TOKlparen)
+    {   error("!(TemplateArgumentList) expected following TemplateIdentifier");
+	return tiargs;
+    }
+    nextToken();
+
+    // Get TemplateArgumentList
+    if (token.value != TOKrparen)
+    {
+	while (1)
+	{
+	    // See if it is an Expression or a Type
+	    if (isDeclaration(&token, 0, TOKreserved, NULL))
+	    {	// Type
+		Type *ta;
+
+		// Get TemplateArgument
+		ta = parseBasicType();
+		ta = parseDeclarator(ta, NULL);
+		tiargs->push(ta);
+	    }
+	    else
+	    {	// Expression
+		Expression *ea;
+
+		ea = parseAssignExp();
+		tiargs->push(ea);
+	    }
+	    if (token.value != TOKcomma)
+		break;
+	    nextToken();
+	}
+    }
+    check(TOKrparen, "template argument list");
+    return tiargs;
+}
+
+Import *Parser::parseImport(Array *decldefs, int isstatic)
+{   Import *s;
+    Identifier *id;
+    Identifier *aliasid = NULL;
+    Array *a;
+    Loc loc;
+
+    //printf("Parser::parseImport()\n");
+    do
+    {
+     L1:
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("Identifier expected following import");
+	    break;
+	}
+
+	loc = this->loc;
+	a = NULL;
+	id = token.ident;
+	nextToken();
+	if (!aliasid && token.value == TOKassign)
+	{
+	    aliasid = id;
+	    goto L1;
+	}
+	while (token.value == TOKdot)
+	{
+	    if (!a)
+		a = new Array();
+	    a->push(id);
+	    nextToken();
+	    if (token.value != TOKidentifier)
+	    {   error("Identifier expected following package");
+		break;
+	    }
+	    id = token.ident;
+	    nextToken();
+	}
+
+	s = new Import(loc, a, token.ident, aliasid, isstatic);
+	decldefs->push(s);
+
+	/* Look for
+	 *	: alias=name, alias=name;
+	 * syntax.
+	 */
+	if (token.value == TOKcolon)
+	{
+	    do
+	    {	Identifier *name;
+		Identifier *alias;
+
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following :");
+		    break;
+		}
+		alias = token.ident;
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value != TOKidentifier)
+		    {   error("Identifier expected following %s=", alias->toChars());
+			break;
+		    }
+		    name = token.ident;
+		    nextToken();
+		}
+		else
+		{   name = alias;
+		    alias = NULL;
+		}
+		s->addAlias(name, alias);
+	    } while (token.value == TOKcomma);
+	    break;	// no comma-separated imports of this form
+	}
+
+	aliasid = NULL;
+    } while (token.value == TOKcomma);
+
+    if (token.value == TOKsemicolon)
+ 	nextToken();
+    else
+    {
+	error("';' expected");
+	nextToken();
+    }
+
+    return NULL;
+}
+
+Type *Parser::parseBasicType()
+{   Type *t;
+    Identifier *id;
+    TypeQualified *tid;
+    TemplateInstance *tempinst;
+
+    //printf("parseBasicType()\n");
+    switch (token.value)
+    {
+	CASE_BASIC_TYPES_X(t):
+	    nextToken();
+	    break;
+
+	case TOKidentifier:
+	    id = token.ident;
+	    nextToken();
+	    if (token.value == TOKnot)
+	    {
+		nextToken();
+		tempinst = new TemplateInstance(loc, id);
+		tempinst->tiargs = parseTemplateArgumentList();
+		tid = new TypeInstance(loc, tempinst);
+		goto Lident2;
+	    }
+	Lident:
+	    tid = new TypeIdentifier(loc, id);
+	Lident2:
+	    while (token.value == TOKdot)
+	    {	nextToken();
+		if (token.value != TOKidentifier)
+		{   error("identifier expected following '.' instead of '%s'", token.toChars());
+		    break;
+		}
+		id = token.ident;
+		nextToken();
+		if (token.value == TOKnot)
+		{
+		    nextToken();
+		    tempinst = new TemplateInstance(loc, id);
+		    tempinst->tiargs = parseTemplateArgumentList();
+		    tid->addIdent((Identifier *)tempinst);
+		}
+		else
+		    tid->addIdent(id);
+	    }
+	    t = tid;
+	    break;
+
+	case TOKdot:
+	    // Leading . as in .foo
+	    id = Id::empty;
+	    goto Lident;
+
+	case TOKtypeof:
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    tid = new TypeTypeof(loc, exp);
+	    goto Lident2;
+	}
+
+	default:
+	    error("basic type expected, not %s", token.toChars());
+	    t = Type::tint32;
+	    break;
+    }
+    return t;
+}
+
+/******************************************
+ * Parse things that follow the initial type t.
+ *	t *
+ *	t []
+ *	t [type]
+ *	t [expression]
+ *	t [expression .. expression]
+ *	t function
+ *	t delegate
+ */
+
+Type *Parser::parseBasicType2(Type *t)
+{
+    Type *ts;
+    Type *ta;
+
+    //printf("parseBasicType2()\n");
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKmul:
+		t = new TypePointer(t);
+		nextToken();
+		continue;
+
+	    case TOKlbracket:
+#if LTORARRAYDECL
+		// Handle []. Make sure things like
+		//     int[3][1] a;
+		// is (array[1] of array[3] of int)
+		nextToken();
+		if (token.value == TOKrbracket)
+		{
+		    t = new TypeDArray(t);			// []
+		    nextToken();
+		}
+		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		{   // It's an associative array declaration
+		    Type *index;
+
+		    //printf("it's an associative array\n");
+		    index = parseBasicType();
+		    index = parseDeclarator(index, NULL);	// [ type ]
+		    t = new TypeAArray(t, index);
+		    check(TOKrbracket);
+		}
+		else
+		{
+		    //printf("it's [expression]\n");
+		    inBrackets++;
+		    Expression *e = parseExpression();		// [ expression ]
+		    if (token.value == TOKslice)
+		    {	Expression *e2;
+
+			nextToken();
+			e2 = parseExpression();			// [ exp .. exp ]
+			t = new TypeSlice(t, e, e2);
+		    }
+		    else
+			t = new TypeSArray(t,e);
+		    inBrackets--;
+		    check(TOKrbracket);
+		}
+		continue;
+#else
+		// Handle []. Make sure things like
+		//     int[3][1] a;
+		// is (array[3] of array[1] of int)
+		ts = t;
+		while (token.value == TOKlbracket)
+		{
+		    nextToken();
+		    if (token.value == TOKrbracket)
+		    {
+			ta = new TypeDArray(t);			// []
+			nextToken();
+		    }
+		    else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		    {   // It's an associative array declaration
+			Type *index;
+
+			//printf("it's an associative array\n");
+			index = parseBasicType();
+			index = parseDeclarator(index, NULL);	// [ type ]
+			check(TOKrbracket);
+			ta = new TypeAArray(t, index);
+		    }
+		    else
+		    {
+			//printf("it's [expression]\n");
+			Expression *e = parseExpression();	// [ expression ]
+			ta = new TypeSArray(t,e);
+			check(TOKrbracket);
+		    }
+		    Type **pt;
+		    for (pt = &ts; *pt != t; pt = &(*pt)->next)
+			;
+		    *pt = ta;
+		}
+		t = ts;
+		continue;
+#endif
+
+	    case TOKdelegate:
+	    case TOKfunction:
+	    {	// Handle delegate declaration:
+		//	t delegate(parameter list)
+		//	t function(parameter list)
+		Arguments *arguments;
+		int varargs;
+		enum TOK save = token.value;
+
+		nextToken();
+		arguments = parseParameters(&varargs);
+		t = new TypeFunction(arguments, t, varargs, linkage);
+		if (save == TOKdelegate)
+		    t = new TypeDelegate(t);
+		else
+		    t = new TypePointer(t);	// pointer to function
+		continue;
+	    }
+
+	    default:
+		ts = t;
+		break;
+	}
+	break;
+    }
+    return ts;
+}
+
+Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
+{   Type *ts;
+    Type *ta;
+
+    //printf("parseDeclarator(tpl = %p)\n", tpl);
+    t = parseBasicType2(t);
+
+    switch (token.value)
+    {
+
+	case TOKidentifier:
+	    if (pident)
+		*pident = token.ident;
+	    else
+		error("unexpected identifer '%s' in declarator", token.ident->toChars());
+	    ts = t;
+	    nextToken();
+	    break;
+
+	case TOKlparen:
+	    /* Parse things with parentheses around the identifier, like:
+	     *	int (*ident[3])[]
+	     * although the D style would be:
+	     *	int[]*[3] ident
+	     */
+	    nextToken();
+	    ts = parseDeclarator(t, pident);
+	    check(TOKrparen);
+	    break;
+
+	default:
+	    ts = t;
+	    break;
+    }
+
+    while (1)
+    {
+	switch (token.value)
+	{
+#if CARRAYDECL
+	    /* Support C style array syntax:
+	     *   int ident[]
+	     * as opposed to D-style:
+	     *   int[] ident
+	     */
+	    case TOKlbracket:
+	    {	// This is the old C-style post [] syntax.
+		nextToken();
+		if (token.value == TOKrbracket)
+		{   // It's a dynamic array
+		    ta = new TypeDArray(t);		// []
+		    nextToken();
+		}
+		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		{   // It's an associative array declaration
+		    Type *index;
+
+		    //printf("it's an associative array\n");
+		    index = parseBasicType();
+		    index = parseDeclarator(index, NULL);	// [ type ]
+		    check(TOKrbracket);
+		    ta = new TypeAArray(t, index);
+		}
+		else
+		{
+		    //printf("it's [expression]\n");
+		    Expression *e = parseExpression();		// [ expression ]
+		    ta = new TypeSArray(t, e);
+		    check(TOKrbracket);
+		}
+		/* Insert ta into
+		 *   ts -> ... -> t
+		 * so that
+		 *   ts -> ... -> ta -> t
+		 */
+		Type **pt;
+		for (pt = &ts; *pt != t; pt = &(*pt)->next)
+		    ;
+		*pt = ta;
+		continue;
+	    }
+#endif
+	    case TOKlparen:
+	    {	Arguments *arguments;
+		int varargs;
+
+		if (tpl)
+		{
+		    /* Look ahead to see if this is (...)(...),
+		     * i.e. a function template declaration
+		     */
+		    if (peekPastParen(&token)->value == TOKlparen)
+		    {   // It's a function template declaration
+			//printf("function template declaration\n");
+
+			// Gather template parameter list
+			*tpl = parseTemplateParameterList();
+		    }
+		}
+
+		arguments = parseParameters(&varargs);
+		Type *ta = new TypeFunction(arguments, t, varargs, linkage);
+		Type **pt;
+		for (pt = &ts; *pt != t; pt = &(*pt)->next)
+		    ;
+		*pt = ta;
+		break;
+	    }
+	}
+	break;
+    }
+
+    return ts;
+}
+
+/**********************************
+ * Parse Declarations.
+ * These can be:
+ *	1. declarations at global/class level
+ *	2. declarations at statement level
+ * Return array of Declaration *'s.
+ */
+
+Array *Parser::parseDeclarations()
+{
+    enum STC storage_class;
+    enum STC stc;
+    Type *ts;
+    Type *t;
+    Type *tfirst;
+    Identifier *ident;
+    Array *a;
+    enum TOK tok;
+    unsigned char *comment = token.blockComment;
+    enum LINK link = linkage;
+
+    //printf("parseDeclarations()\n");
+    switch (token.value)
+    {
+	case TOKtypedef:
+	case TOKalias:
+	    tok = token.value;
+	    nextToken();
+	    break;
+
+	default:
+	    tok = TOKreserved;
+	    break;
+    }
+
+    storage_class = STCundefined;
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKconst:	stc = STCconst;		 goto L1;
+	    case TOKstatic:	stc = STCstatic;	 goto L1;
+	    case TOKfinal:	stc = STCfinal;		 goto L1;
+	    case TOKauto:	stc = STCauto;		 goto L1;
+	    case TOKscope:	stc = STCscope;		 goto L1;
+	    case TOKoverride:	stc = STCoverride;	 goto L1;
+	    case TOKabstract:	stc = STCabstract;	 goto L1;
+	    case TOKsynchronized: stc = STCsynchronized; goto L1;
+	    case TOKdeprecated: stc = STCdeprecated;	 goto L1;
+	    L1:
+		if (storage_class & stc)
+		    error("redundant storage class '%s'", token.toChars());
+		storage_class = (STC) (storage_class | stc);
+		nextToken();
+		continue;
+
+	    case TOKextern:
+		if (peek(&token)->value != TOKlparen)
+		{   stc = STCextern;
+		    goto L1;
+		}
+
+		link = parseLinkage();
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+
+    a = new Array();
+
+    /* Look for auto initializers:
+     *	storage_class identifier = initializer;
+     */
+    while (storage_class &&
+	token.value == TOKidentifier &&
+	peek(&token)->value == TOKassign)
+    {
+	ident = token.ident;
+	nextToken();
+	nextToken();
+	Initializer *init = parseInitializer();
+	VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+	v->storage_class = storage_class;
+	a->push(v);
+	if (token.value == TOKsemicolon)
+	{
+	    nextToken();
+	    addComment(v, comment);
+	}
+	else if (token.value == TOKcomma)
+	{
+	    nextToken();
+	    if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
+	    {
+		error("Identifier expected following comma");
+	    }
+	    else
+		continue;
+	}
+	else
+	    error("semicolon expected following auto declaration, not '%s'", token.toChars());
+	return a;
+    }
+
+    if (token.value == TOKclass)
+    {	AggregateDeclaration *s;
+
+	s = (AggregateDeclaration *)parseAggregate();
+	s->storage_class |= storage_class;
+	a->push(s);
+	addComment(s, comment);
+	return a;
+    }
+
+    ts = parseBasicType();
+    ts = parseBasicType2(ts);
+    tfirst = NULL;
+
+    while (1)
+    {
+	Loc loc = this->loc;
+	TemplateParameters *tpl = NULL;
+
+	ident = NULL;
+	t = parseDeclarator(ts, &ident, &tpl);
+	assert(t);
+	if (!tfirst)
+	    tfirst = t;
+	else if (t != tfirst)
+	    error("multiple declarations must have the same type, not %s and %s",
+		tfirst->toChars(), t->toChars());
+	if (!ident)
+	    error("no identifier for declarator %s", t->toChars());
+
+	if (tok == TOKtypedef || tok == TOKalias)
+	{   Declaration *v;
+	    Initializer *init;
+
+	    init = NULL;
+	    if (token.value == TOKassign)
+	    {
+		nextToken();
+		init = parseInitializer();
+	    }
+	    if (tok == TOKtypedef)
+		v = new TypedefDeclaration(loc, ident, t, init);
+	    else
+	    {	if (init)
+		    error("alias cannot have initializer");
+		v = new AliasDeclaration(loc, ident, t);
+	    }
+	    v->storage_class = storage_class;
+	    if (link == linkage)
+		a->push(v);
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(v);
+		Dsymbol *s = new LinkDeclaration(link, ax);
+		a->push(s);
+	    }
+	    switch (token.value)
+	    {   case TOKsemicolon:
+		    nextToken();
+		    addComment(v, comment);
+		    break;
+
+		case TOKcomma:
+		    nextToken();
+		    addComment(v, comment);
+		    continue;
+
+		default:
+		    error("semicolon expected to close %s declaration", Token::toChars(tok));
+		    break;
+	    }
+	}
+	else if (t->ty == Tfunction)
+	{   FuncDeclaration *f;
+	    Dsymbol *s;
+
+	    f = new FuncDeclaration(loc, 0, ident, storage_class, t);
+	    addComment(f, comment);
+	    parseContracts(f);
+	    addComment(f, NULL);
+	    if (link == linkage)
+	    {
+		s = f;
+	    }
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(f);
+		s = new LinkDeclaration(link, ax);
+	    }
+	    if (tpl)			// it's a function template
+	    {   Array *decldefs;
+		TemplateDeclaration *tempdecl;
+
+		// Wrap a template around the aggregate declaration
+		decldefs = new Array();
+		decldefs->push(s);
+		tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs);
+		s = tempdecl;
+	    }
+	    addComment(s, comment);
+	    a->push(s);
+	}
+	else
+	{   VarDeclaration *v;
+	    Initializer *init;
+
+	    init = NULL;
+	    if (token.value == TOKassign)
+	    {
+		nextToken();
+		init = parseInitializer();
+	    }
+	    v = new VarDeclaration(loc, t, ident, init);
+	    v->storage_class = storage_class;
+	    if (link == linkage)
+		a->push(v);
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(v);
+		Dsymbol *s = new LinkDeclaration(link, ax);
+		a->push(s);
+	    }
+	    switch (token.value)
+	    {   case TOKsemicolon:
+		    nextToken();
+		    addComment(v, comment);
+		    break;
+
+		case TOKcomma:
+		    nextToken();
+		    addComment(v, comment);
+		    continue;
+
+		default:
+		    error("semicolon expected, not '%s'", token.toChars());
+		    break;
+	    }
+	}
+	break;
+    }
+    return a;
+}
+
+/*****************************************
+ * Parse auto declarations of the form:
+ *   storageClass ident = init, ident = init, ... ;
+ * and return the array of them.
+ * Starts with token on the first ident.
+ * Ends with scanner past closing ';'
+ */
+
+#if DMDV2
+Array *Parser::parseAutoDeclarations(unsigned storageClass, unsigned char *comment)
+{
+    Array *a = new Array;
+
+    while (1)
+    {
+	Identifier *ident = token.ident;
+	nextToken();		// skip over ident
+	assert(token.value == TOKassign);
+	nextToken();		// skip over '='
+	Initializer *init = parseInitializer();
+	VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+	v->storage_class = storageClass;
+	a->push(v);
+	if (token.value == TOKsemicolon)
+	{
+	    nextToken();
+	    addComment(v, comment);
+	}
+	else if (token.value == TOKcomma)
+	{
+	    nextToken();
+	    if (token.value == TOKidentifier &&
+		peek(&token)->value == TOKassign)
+	    {
+		addComment(v, comment);
+		continue;
+	    }
+	    else
+		error("Identifier expected following comma");
+	}
+	else
+	    error("semicolon expected following auto declaration, not '%s'", token.toChars());
+	break;
+    }
+    return a;
+}
+#endif
+
+/*****************************************
+ * Parse contracts following function declaration.
+ */
+
+void Parser::parseContracts(FuncDeclaration *f)
+{
+    Type *tb;
+    enum LINK linksave = linkage;
+
+    // The following is irrelevant, as it is overridden by sc->linkage in
+    // TypeFunction::semantic
+    linkage = LINKd;		// nested functions have D linkage
+L1:
+    switch (token.value)
+    {
+	case TOKlcurly:
+	    if (f->frequire || f->fensure)
+		error("missing body { ... } after in or out");
+	    f->fbody = parseStatement(PSsemi);
+	    f->endloc = endloc;
+	    break;
+
+	case TOKbody:
+	    nextToken();
+	    f->fbody = parseStatement(PScurly);
+	    f->endloc = endloc;
+	    break;
+
+	case TOKsemicolon:
+	    if (f->frequire || f->fensure)
+		error("missing body { ... } after in or out");
+	    nextToken();
+	    break;
+
+#if 0	// Do we want this for function declarations, so we can do:
+    // int x, y, foo(), z;
+	case TOKcomma:
+	    nextToken();
+	    continue;
+#endif
+
+#if 0 // Dumped feature
+	case TOKthrow:
+	    if (!f->fthrows)
+		f->fthrows = new Array();
+	    nextToken();
+	    check(TOKlparen);
+	    while (1)
+	    {
+		tb = parseBasicType();
+		f->fthrows->push(tb);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	    }
+	    check(TOKrparen);
+	    goto L1;
+#endif
+
+	case TOKin:
+	    nextToken();
+	    if (f->frequire)
+		error("redundant 'in' statement");
+	    f->frequire = parseStatement(PScurly | PSscope);
+	    goto L1;
+
+	case TOKout:
+	    // parse: out (identifier) { statement }
+	    nextToken();
+	    if (token.value != TOKlcurly)
+	    {
+		check(TOKlparen);
+		if (token.value != TOKidentifier)	   
+		    error("(identifier) following 'out' expected, not %s", token.toChars());
+		f->outId = token.ident;
+		nextToken();
+		check(TOKrparen);
+	    }
+	    if (f->fensure)
+		error("redundant 'out' statement");
+	    f->fensure = parseStatement(PScurly | PSscope);
+	    goto L1;
+
+	default:
+	    error("semicolon expected following function declaration");
+	    break;
+    }
+    linkage = linksave;
+}
+
+/*****************************************
+ */
+
+Initializer *Parser::parseInitializer()
+{
+    StructInitializer *is;
+    ArrayInitializer *ia;
+    ExpInitializer *ie;
+    Expression *e;
+    Identifier *id;
+    Initializer *value;
+    int comma;
+    Loc loc = this->loc;
+    Token *t;
+    int braces;
+
+    switch (token.value)
+    {
+	case TOKlcurly:
+	    /* Scan ahead to see if it is a struct initializer or
+	     * a function literal.
+	     * If it contains a ';', it is a function literal.
+	     * Treat { } as a struct initializer.
+	     */
+	    braces = 1;
+	    for (t = peek(&token); 1; t = peek(t))
+	    {
+		switch (t->value)
+		{
+		    case TOKsemicolon:
+		    case TOKreturn:
+			goto Lexpression;
+
+		    case TOKlcurly:
+			braces++;
+			continue;
+
+		    case TOKrcurly:
+			if (--braces == 0)
+			    break;
+			continue;
+
+		    case TOKeof:
+			break;
+
+		    default:
+			continue;
+		}
+		break;
+	    }
+
+	    is = new StructInitializer(loc);
+	    nextToken();
+	    comma = 0;
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    case TOKidentifier:
+			if (comma == 1)
+			    error("comma expected separating field initializers");
+			t = peek(&token);
+			if (t->value == TOKcolon)
+			{
+			    id = token.ident;
+			    nextToken();
+			    nextToken();	// skip over ':'
+			}
+			else
+			{   id = NULL;
+			}
+			value = parseInitializer();
+			is->addInit(id, value);
+			comma = 1;
+			continue;
+
+		    case TOKcomma:
+			nextToken();
+			comma = 2;
+			continue;
+
+		    case TOKrcurly:		// allow trailing comma's
+			nextToken();
+			break;
+
+		    case TOKeof:
+			error("found EOF instead of initializer");
+			break;
+
+		    default:
+			value = parseInitializer();
+			is->addInit(NULL, value);
+			comma = 1;
+			continue;
+			//error("found '%s' instead of field initializer", token.toChars());
+			//break;
+		}
+		break;
+	    }
+	    return is;
+
+	case TOKlbracket:
+	    ia = new ArrayInitializer(loc);
+	    nextToken();
+	    comma = 0;
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    default:
+			if (comma == 1)
+			{   error("comma expected separating array initializers, not %s", token.toChars());
+			    nextToken();
+			    break;
+			}
+			e = parseAssignExp();
+			if (!e)
+			    break;
+			if (token.value == TOKcolon)
+			{
+			    nextToken();
+			    value = parseInitializer();
+			}
+			else
+			{   value = new ExpInitializer(e->loc, e);
+			    e = NULL;
+			}
+			ia->addInit(e, value);
+			comma = 1;
+			continue;
+
+		    case TOKlcurly:
+		    case TOKlbracket:
+			if (comma == 1)
+			    error("comma expected separating array initializers, not %s", token.toChars());
+			value = parseInitializer();
+			ia->addInit(NULL, value);
+			comma = 1;
+			continue;
+
+		    case TOKcomma:
+			nextToken();
+			comma = 2;
+			continue;
+
+		    case TOKrbracket:		// allow trailing comma's
+			nextToken();
+			break;
+
+		    case TOKeof:
+			error("found '%s' instead of array initializer", token.toChars());
+			break;
+		}
+		break;
+	    }
+	    return ia;
+
+	case TOKvoid:
+	    t = peek(&token);
+	    if (t->value == TOKsemicolon || t->value == TOKcomma)
+	    {
+		nextToken();
+		return new VoidInitializer(loc);
+	    }
+	    goto Lexpression;
+
+	default:
+	Lexpression:
+	    e = parseAssignExp();
+	    ie = new ExpInitializer(loc, e);
+	    return ie;
+    }
+}
+
+/*****************************************
+ * Parses default argument initializer expression that is an assign expression,
+ * with special handling for __FILE__ and __LINE__.
+ */
+
+#if DMDV2
+Expression *Parser::parseDefaultInitExp()
+{
+    if (token.value == TOKfile ||
+	token.value == TOKline)
+    {
+	Token *t = peek(&token);
+	if (t->value == TOKcomma || t->value == TOKrparen)
+	{   Expression *e;
+
+	    if (token.value == TOKfile)
+		e = new FileInitExp(loc);
+	    else
+		e = new LineInitExp(loc);
+	    nextToken();
+	    return e;
+	}
+    }
+
+    Expression *e = parseAssignExp();
+    return e;
+}
+#endif
+
+/*****************************************
+ * Input:
+ *	flags	PSxxxx
+ */
+
+Statement *Parser::parseStatement(int flags)
+{   Statement *s;
+    Token *t;
+    Condition *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+    Loc loc = this->loc;
+
+    //printf("parseStatement()\n");
+
+    if (flags & PScurly && token.value != TOKlcurly)
+	error("statement expected to be { }, not %s", token.toChars());
+
+    switch (token.value)
+    {
+	case TOKidentifier:
+	    // Need to look ahead to see if it is a declaration, label, or expression
+	    t = peek(&token);
+	    if (t->value == TOKcolon)
+	    {	// It's a label
+		Identifier *ident;
+
+		ident = token.ident;
+		nextToken();
+		nextToken();
+		s = parseStatement(PSsemi);
+		s = new LabelStatement(loc, ident, s);
+		break;
+	    }
+	    // fallthrough to TOKdot
+	case TOKdot:
+	case TOKtypeof:
+	    if (isDeclaration(&token, 2, TOKreserved, NULL))
+		goto Ldeclaration;
+	    else
+		goto Lexp;
+	    break;
+
+	case TOKassert:
+	case TOKthis:
+	case TOKsuper:
+	case TOKint32v:
+	case TOKuns32v:
+	case TOKint64v:
+	case TOKuns64v:
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	case TOKimaginary32v:
+	case TOKimaginary64v:
+	case TOKimaginary80v:
+	case TOKcharv:
+	case TOKwcharv:
+	case TOKdcharv:
+	case TOKnull:
+	case TOKtrue:
+	case TOKfalse:
+	case TOKstring:
+	case TOKlparen:
+	case TOKcast:
+	case TOKmul:
+	case TOKmin:
+	case TOKadd:
+	case TOKplusplus:
+	case TOKminusminus:
+	case TOKnew:
+	case TOKdelete:
+	case TOKdelegate:
+	case TOKfunction:
+	case TOKtypeid:
+	case TOKis:
+	case TOKlbracket:
+#if DMDV2
+	case TOKtraits:
+	case TOKfile:
+	case TOKline:
+#endif
+	Lexp:
+	{   Expression *exp;
+
+	    exp = parseExpression();
+	    check(TOKsemicolon, "statement");
+	    s = new ExpStatement(loc, exp);
+	    break;
+	}
+
+	case TOKstatic:
+	{   // Look ahead to see if it's static assert() or static if()
+	    Token *t;
+
+	    t = peek(&token);
+	    if (t->value == TOKassert)
+	    {
+		nextToken();
+		s = new StaticAssertStatement(parseStaticAssert());
+		break;
+	    }
+	    if (t->value == TOKif)
+	    {
+		nextToken();
+		condition = parseStaticIfCondition();
+		goto Lcondition;
+	    }
+	    goto Ldeclaration;
+	}
+
+	CASE_BASIC_TYPES:
+	case TOKtypedef:
+	case TOKalias:
+	case TOKconst:
+	case TOKauto:
+	case TOKextern:
+	case TOKfinal:
+	case TOKinvariant:
+//	case TOKtypeof:
+	Ldeclaration:
+	{   Array *a;
+
+	    a = parseDeclarations();
+	    if (a->dim > 1)
+	    {
+		Statements *as = new Statements();
+		as->reserve(a->dim);
+		for (int i = 0; i < a->dim; i++)
+		{
+		    Dsymbol *d = (Dsymbol *)a->data[i];
+		    s = new DeclarationStatement(loc, d);
+		    as->push(s);
+		}
+		s = new CompoundStatement(loc, as);
+	    }
+	    else if (a->dim == 1)
+	    {
+		Dsymbol *d = (Dsymbol *)a->data[0];
+		s = new DeclarationStatement(loc, d);
+	    }
+	    else
+		assert(0);
+	    if (flags & PSscope)
+		s = new ScopeStatement(loc, s);
+	    break;
+	}
+
+	case TOKstruct:
+	case TOKunion:
+	case TOKclass:
+	case TOKinterface:
+	{   Dsymbol *d;
+
+	    d = parseAggregate();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKenum:
+	{   Dsymbol *d;
+
+	    d = parseEnum();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKmixin:
+	{   t = peek(&token);
+	    if (t->value == TOKlparen)
+	    {	// mixin(string)
+		nextToken();
+		check(TOKlparen, "mixin");
+		Expression *e = parseAssignExp();
+		check(TOKrparen);
+		check(TOKsemicolon);
+		s = new CompileStatement(loc, e);
+		break;
+	    }
+	    Dsymbol *d = parseMixin();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKlcurly:
+	{   Statements *statements;
+
+	    nextToken();
+	    statements = new Statements();
+	    while (token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    endloc = this->loc;
+	    s = new CompoundStatement(loc, statements);
+	    if (flags & (PSscope | PScurlyscope))
+		s = new ScopeStatement(loc, s);
+	    nextToken();
+	    break;
+	}
+
+	case TOKwhile:
+	{   Expression *condition;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new WhileStatement(loc, condition, body);
+	    break;
+	}
+
+	case TOKsemicolon:
+	    if (!(flags & PSsemi))
+		error("use '{ }' for an empty statement, not a ';'");
+	    nextToken();
+	    s = new ExpStatement(loc, NULL);
+	    break;
+
+	case TOKdo:
+	{   Statement *body;
+	    Expression *condition;
+
+	    nextToken();
+	    body = parseStatement(PSscope);
+	    check(TOKwhile);
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    s = new DoStatement(loc, body, condition);
+	    break;
+	}
+
+	case TOKfor:
+	{
+	    Statement *init;
+	    Expression *condition;
+	    Expression *increment;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value == TOKsemicolon)
+	    {	init = NULL;
+		nextToken();
+	    }
+	    else
+	    {	init = parseStatement(0);
+	    }
+	    if (token.value == TOKsemicolon)
+	    {
+		condition = NULL;
+		nextToken();
+	    }
+	    else
+	    {
+		condition = parseExpression();
+		check(TOKsemicolon, "for condition");
+	    }
+	    if (token.value == TOKrparen)
+	    {	increment = NULL;
+		nextToken();
+	    }
+	    else
+	    {	increment = parseExpression();
+		check(TOKrparen);
+	    }
+	    body = parseStatement(PSscope);
+	    s = new ForStatement(loc, init, condition, increment, body);
+	    if (init)
+		s = new ScopeStatement(loc, s);
+	    break;
+	}
+
+	case TOKforeach:
+	case TOKforeach_reverse:
+	{
+	    enum TOK op = token.value;
+	    Arguments *arguments;
+
+	    Statement *d;
+	    Statement *body;
+	    Expression *aggr;
+
+	    nextToken();
+	    check(TOKlparen);
+
+	    arguments = new Arguments();
+
+	    while (1)
+	    {
+		Type *tb;
+		Identifier *ai = NULL;
+		Type *at;
+		unsigned storageClass;
+		Argument *a;
+
+		storageClass = STCin;
+		if (token.value == TOKinout || token.value == TOKref)
+		{   storageClass = STCref;
+		    nextToken();
+		}
+		if (token.value == TOKidentifier)
+		{
+		    Token *t = peek(&token);
+		    if (t->value == TOKcomma || t->value == TOKsemicolon)
+		    {	ai = token.ident;
+			at = NULL;		// infer argument type
+			nextToken();
+			goto Larg;
+		    }
+		}
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		if (!ai)
+		    error("no identifier for declarator %s", at->toChars());
+	      Larg:
+		a = new Argument(storageClass, at, ai, NULL);
+		arguments->push(a);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	    }
+	    check(TOKsemicolon);
+
+	    aggr = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(0);
+	    s = new ForeachStatement(loc, op, arguments, aggr, body);
+	    break;
+	}
+
+	case TOKif:
+	{   Argument *arg = NULL;
+	    Expression *condition;
+	    Statement *ifbody;
+	    Statement *elsebody;
+
+	    nextToken();
+	    check(TOKlparen);
+
+	    if (token.value == TOKauto)
+	    {
+		nextToken();
+		if (token.value == TOKidentifier)
+		{
+		    Token *t = peek(&token);
+		    if (t->value == TOKassign)
+		    {
+			arg = new Argument(STCin, NULL, token.ident, NULL);
+			nextToken();
+			nextToken();
+		    }
+		    else
+		    {   error("= expected following auto identifier");
+			goto Lerror;
+		    }
+		}
+		else
+		{   error("identifier expected following auto");
+		    goto Lerror;
+		}
+	    }
+	    else if (isDeclaration(&token, 2, TOKassign, NULL))
+	    {
+		Type *tb;
+		Type *at;
+		Identifier *ai;
+
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		check(TOKassign);
+		arg = new Argument(STCin, at, ai, NULL);
+	    }
+
+	    // Check for " ident;"
+	    else if (token.value == TOKidentifier)
+	    {
+		Token *t = peek(&token);
+		if (t->value == TOKcomma || t->value == TOKsemicolon)
+		{
+		    arg = new Argument(STCin, NULL, token.ident, NULL);
+		    nextToken();
+		    nextToken();
+		    if (1 || !global.params.useDeprecated)
+			error("if (v; e) is deprecated, use if (auto v = e)");
+		}
+	    }
+
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    ifbody = parseStatement(PSscope);
+	    if (token.value == TOKelse)
+	    {
+		nextToken();
+		elsebody = parseStatement(PSscope);
+	    }
+	    else
+		elsebody = NULL;
+	    s = new IfStatement(loc, arg, condition, ifbody, elsebody);
+	    break;
+	}
+
+	case TOKscope:
+	    if (peek(&token)->value != TOKlparen)
+		goto Ldeclaration;		// scope used as storage class
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value != TOKidentifier)
+	    {	error("scope identifier expected");
+		goto Lerror;
+	    }
+	    else
+	    {	TOK t = TOKon_scope_exit;
+		Identifier *id = token.ident;
+
+		if (id == Id::exit)
+		    t = TOKon_scope_exit;
+		else if (id == Id::failure)
+		    t = TOKon_scope_failure;
+		else if (id == Id::success)
+		    t = TOKon_scope_success;
+		else
+		    error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
+		nextToken();
+		check(TOKrparen);
+		Statement *st = parseStatement(PScurlyscope);
+		s = new OnScopeStatement(loc, t, st);
+		break;
+	    }
+
+	case TOKdebug:
+	    nextToken();
+	    condition = parseDebugCondition();
+	    goto Lcondition;
+
+	case TOKversion:
+	    nextToken();
+	    condition = parseVersionCondition();
+	    goto Lcondition;
+
+	Lcondition:
+	    ifbody = parseStatement(0 /*PSsemi*/);
+	    elsebody = NULL;
+	    if (token.value == TOKelse)
+	    {
+		nextToken();
+		elsebody = parseStatement(0 /*PSsemi*/);
+	    }
+	    s = new ConditionalStatement(loc, condition, ifbody, elsebody);
+	    break;
+
+	case TOKpragma:
+	{   Identifier *ident;
+	    Expressions *args = NULL;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value != TOKidentifier)
+	    {   error("pragma(identifier expected");
+		goto Lerror;
+	    }
+	    ident = token.ident;
+	    nextToken();
+	    if (token.value == TOKcomma)
+		args = parseArguments();	// pragma(identifier, args...);
+	    else
+		check(TOKrparen);		// pragma(identifier);
+	    if (token.value == TOKsemicolon)
+	    {	nextToken();
+		body = NULL;
+	    }
+	    else
+		body = parseStatement(PSsemi);
+	    s = new PragmaStatement(loc, ident, args, body);
+	    break;
+	}
+
+	case TOKswitch:
+	{   Expression *condition;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new SwitchStatement(loc, condition, body);
+	    break;
+	}
+
+	case TOKcase:
+	{   Expression *exp;
+	    Statements *statements;
+	    Array cases;	// array of Expression's
+
+	    while (1)
+	    {
+		nextToken();
+		exp = parseAssignExp();
+		cases.push(exp);
+		if (token.value != TOKcomma)
+		    break;
+	    }
+	    check(TOKcolon);
+
+	    statements = new Statements();
+	    while (token.value != TOKcase &&
+		   token.value != TOKdefault &&
+		   token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    s = new CompoundStatement(loc, statements);
+	    s = new ScopeStatement(loc, s);
+
+	    // Keep cases in order by building the case statements backwards
+	    for (int i = cases.dim; i; i--)
+	    {
+		exp = (Expression *)cases.data[i - 1];
+		s = new CaseStatement(loc, exp, s);
+	    }
+	    break;
+	}
+
+	case TOKdefault:
+	{
+	    Statements *statements;
+
+	    nextToken();
+	    check(TOKcolon);
+
+	    statements = new Statements();
+	    while (token.value != TOKcase &&
+		   token.value != TOKdefault &&
+		   token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    s = new CompoundStatement(loc, statements);
+	    s = new ScopeStatement(loc, s);
+	    s = new DefaultStatement(loc, s);
+	    break;
+	}
+
+	case TOKreturn:
+	{   Expression *exp;
+
+	    nextToken();
+	    if (token.value == TOKsemicolon)
+		exp = NULL;
+	    else
+		exp = parseExpression();
+	    check(TOKsemicolon, "return statement");
+	    s = new ReturnStatement(loc, exp);
+	    break;
+	}
+
+	case TOKbreak:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKidentifier)
+	    {	ident = token.ident;
+		nextToken();
+	    }
+	    else
+		ident = NULL;
+	    check(TOKsemicolon, "break statement");
+	    s = new BreakStatement(loc, ident);
+	    break;
+	}
+
+	case TOKcontinue:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKidentifier)
+	    {	ident = token.ident;
+		nextToken();
+	    }
+	    else
+		ident = NULL;
+	    check(TOKsemicolon, "continue statement");
+	    s = new ContinueStatement(loc, ident);
+	    break;
+	}
+
+	case TOKgoto:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKdefault)
+	    {
+		nextToken();
+		s = new GotoDefaultStatement(loc);
+	    }
+	    else if (token.value == TOKcase)
+	    {
+		Expression *exp = NULL;
+
+		nextToken();
+		if (token.value != TOKsemicolon)
+		    exp = parseExpression();
+		s = new GotoCaseStatement(loc, exp);
+	    }
+	    else
+	    {
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following goto");
+		    ident = NULL;
+		}
+		else
+		{   ident = token.ident;
+		    nextToken();
+		}
+		s = new GotoStatement(loc, ident);
+	    }
+	    check(TOKsemicolon, "goto statement");
+	    break;
+	}
+
+	case TOKsynchronized:
+	{   Expression *exp;
+	    Statement *body;
+
+	    nextToken();
+	    if (token.value == TOKlparen)
+	    {
+		nextToken();
+		exp = parseExpression();
+		check(TOKrparen);
+	    }
+	    else
+		exp = NULL;
+	    body = parseStatement(PSscope);
+	    s = new SynchronizedStatement(loc, exp, body);
+	    break;
+	}
+
+	case TOKwith:
+	{   Expression *exp;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new WithStatement(loc, exp, body);
+	    break;
+	}
+
+	case TOKtry:
+	{   Statement *body;
+	    Array *catches = NULL;
+	    Statement *finalbody = NULL;
+
+	    nextToken();
+	    body = parseStatement(PSscope);
+	    while (token.value == TOKcatch)
+	    {
+		Statement *handler;
+		Catch *c;
+		Type *t;
+		Identifier *id;
+		Loc loc = this->loc;
+
+		nextToken();
+		if (token.value == TOKlcurly)
+		{
+		    t = NULL;
+		    id = NULL;
+		}
+		else
+		{
+		    check(TOKlparen);
+		    t = parseBasicType();
+		    id = NULL;
+		    t = parseDeclarator(t, &id);
+		    check(TOKrparen);
+		}
+		handler = parseStatement(0);
+		c = new Catch(loc, t, id, handler);
+		if (!catches)
+		    catches = new Array();
+		catches->push(c);
+	    }
+
+	    if (token.value == TOKfinally)
+	    {	nextToken();
+		finalbody = parseStatement(0);
+	    }
+
+	    s = body;
+	    if (!catches && !finalbody)
+		error("catch or finally expected following try");
+	    else
+	    {	if (catches)
+		    s = new TryCatchStatement(loc, body, catches);
+		if (finalbody)
+		    s = new TryFinallyStatement(loc, s, finalbody);
+	    }
+	    break;
+	}
+
+	case TOKthrow:
+	{   Expression *exp;
+
+	    nextToken();
+	    exp = parseExpression();
+	    check(TOKsemicolon, "throw statement");
+	    s = new ThrowStatement(loc, exp);
+	    break;
+	}
+
+	case TOKvolatile:
+	    nextToken();
+	    s = parseStatement(PSsemi | PScurlyscope);
+#if DMDV2
+	    if (!global.params.useDeprecated)
+		error("volatile statements deprecated; used synchronized statements instead");
+#endif
+	    s = new VolatileStatement(loc, s);
+	    break;
+
+	case TOKasm:
+	{   Statements *statements;
+	    Identifier *label;
+	    Loc labelloc;
+	    Token *toklist;
+	    Token **ptoklist;
+
+	    // Parse the asm block into a sequence of AsmStatements,
+	    // each AsmStatement is one instruction.
+	    // Separate out labels.
+	    // Defer parsing of AsmStatements until semantic processing.
+
+	    nextToken();
+	    check(TOKlcurly);
+	    toklist = NULL;
+	    ptoklist = &toklist;
+	    label = NULL;
+	    statements = new Statements();
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    case TOKidentifier:
+			if (!toklist)
+			{
+			    // Look ahead to see if it is a label
+			    t = peek(&token);
+			    if (t->value == TOKcolon)
+			    {   // It's a label
+				label = token.ident;
+				labelloc = this->loc;
+				nextToken();
+				nextToken();
+				continue;
+			    }
+			}
+			goto Ldefault;
+
+		    case TOKrcurly:
+			if (toklist || label)
+			{
+			    error("asm statements must end in ';'");
+			}
+			break;
+
+		    case TOKsemicolon:
+			s = NULL;
+			if (toklist || label)
+			{   // Create AsmStatement from list of tokens we've saved
+			    s = new AsmStatement(this->loc, toklist);
+			    toklist = NULL;
+			    ptoklist = &toklist;
+			    if (label)
+			    {   s = new LabelStatement(labelloc, label, s);
+				label = NULL;
+			    }
+			    statements->push(s);
+			}
+			nextToken();
+			continue;
+
+		    case TOKeof:
+			/* { */
+			error("matching '}' expected, not end of file");
+			break;
+
+		    default:
+		    Ldefault:
+			*ptoklist = new Token();
+			memcpy(*ptoklist, &token, sizeof(Token));
+			ptoklist = &(*ptoklist)->next;
+			*ptoklist = NULL;
+
+			nextToken();
+			continue;
+		}
+		break;
+	    }
+        s = new AsmBlockStatement(loc, statements);
+	    nextToken();
+	    break;
+	}
+
+	default:
+	    error("found '%s' instead of statement", token.toChars());
+	    goto Lerror;
+
+	Lerror:
+	    while (token.value != TOKrcurly &&
+		   token.value != TOKsemicolon &&
+		   token.value != TOKeof)
+		nextToken();
+	    if (token.value == TOKsemicolon)
+		nextToken();
+	    s = NULL;
+	    break;
+    }
+
+    return s;
+}
+
+void Parser::check(enum TOK value)
+{
+    check(loc, value);
+}
+
+void Parser::check(Loc loc, enum TOK value)
+{
+    if (token.value != value)
+	error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
+    nextToken();
+}
+
+void Parser::check(enum TOK value, char *string)
+{
+    if (token.value != value)
+	error("found '%s' when expecting '%s' following '%s'",
+	    token.toChars(), Token::toChars(value), string);
+    nextToken();
+}
+
+/************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Input:
+ *	needId	0	no identifier
+ *		1	identifier optional
+ *		2	must have identifier
+ */
+
+int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
+{
+    int haveId = 0;
+
+#if DMDV2
+    if ((t->value == TOKconst || t->value == TOKinvariant) &&
+	peek(t)->value != TOKlparen)
+    {	/* const type
+	 * invariant type
+	 */
+	t = peek(t);
+    }
+#endif
+
+    if (!isBasicType(&t))
+	return FALSE;
+    if (!isDeclarator(&t, &haveId, endtok))
+	return FALSE;
+    if ( needId == 1 ||
+	(needId == 0 && !haveId) ||
+	(needId == 2 &&  haveId))
+    {	if (pt)
+	    *pt = t;
+	return TRUE;
+    }
+    else
+	return FALSE;
+}
+
+int Parser::isBasicType(Token **pt)
+{
+    // This code parallels parseBasicType()
+    Token *t = *pt;
+    Token *t2;
+    int parens;
+
+    switch (t->value)
+    {
+	CASE_BASIC_TYPES:
+	    t = peek(t);
+	    break;
+
+	case TOKidentifier:
+	    t = peek(t);
+	    if (t->value == TOKnot)
+	    {
+		goto L4;
+	    }
+	    goto L3;
+	    while (1)
+	    {
+	L2:
+		t = peek(t);
+	L3:
+		if (t->value == TOKdot)
+		{
+	Ldot:
+		    t = peek(t);
+		    if (t->value != TOKidentifier)
+			goto Lfalse;
+		    t = peek(t);
+		    if (t->value != TOKnot)
+			goto L3;
+	L4:
+		    t = peek(t);
+		    if (t->value != TOKlparen)
+			goto Lfalse;
+		    if (!skipParens(t, &t))
+			goto Lfalse;
+		}
+		else
+		    break;
+	    }
+	    break;
+
+	case TOKdot:
+	    goto Ldot;
+
+	case TOKtypeof:
+	    /* typeof(exp).identifier...
+	     */
+	    t = peek(t);
+	    if (t->value != TOKlparen)
+		goto Lfalse;
+	    if (!skipParens(t, &t))
+		goto Lfalse;
+	    goto L2;
+
+	default:
+	    goto Lfalse;
+    }
+    *pt = t;
+    return TRUE;
+
+Lfalse:
+    return FALSE;
+}
+
+int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
+{   // This code parallels parseDeclarator()
+    Token *t = *pt;
+    int parens;
+
+    //printf("Parser::isDeclarator()\n");
+    //t->print();
+    if (t->value == TOKassign)
+	return FALSE;
+
+    while (1)
+    {
+	parens = FALSE;
+	switch (t->value)
+	{
+	    case TOKmul:
+	    case TOKand:
+		t = peek(t);
+		continue;
+
+	    case TOKlbracket:
+		t = peek(t);
+		if (t->value == TOKrbracket)
+		{
+		    t = peek(t);
+		}
+		else if (isDeclaration(t, 0, TOKrbracket, &t))
+		{   // It's an associative array declaration
+		    t = peek(t);
+		}
+		else
+		{
+		    // [ expression ]
+		    // [ expression .. expression ]
+		    if (!isExpression(&t))
+			return FALSE;
+		    if (t->value == TOKslice)
+		    {	t = peek(t);
+			if (!isExpression(&t))
+			    return FALSE;
+		    }
+		    if (t->value != TOKrbracket)
+			return FALSE;
+		    t = peek(t);
+		}
+		continue;
+
+	    case TOKidentifier:
+		if (*haveId)
+		    return FALSE;
+		*haveId = TRUE;
+		t = peek(t);
+		break;
+
+	    case TOKlparen:
+		t = peek(t);
+
+		if (t->value == TOKrparen)
+		    return FALSE;		// () is not a declarator
+
+		/* Regard ( identifier ) as not a declarator
+		 * BUG: what about ( *identifier ) in
+		 *	f(*p)(x);
+		 * where f is a class instance with overloaded () ?
+		 * Should we just disallow C-style function pointer declarations?
+		 */
+		if (t->value == TOKidentifier)
+		{   Token *t2 = peek(t);
+		    if (t2->value == TOKrparen)
+			return FALSE;
+		}
+
+
+		if (!isDeclarator(&t, haveId, TOKrparen))
+		    return FALSE;
+		t = peek(t);
+		parens = TRUE;
+		break;
+
+	    case TOKdelegate:
+	    case TOKfunction:
+		t = peek(t);
+		if (!isParameters(&t))
+		    return FALSE;
+		continue;
+	}
+	break;
+    }
+
+    while (1)
+    {
+	switch (t->value)
+	{
+#if CARRAYDECL
+	    case TOKlbracket:
+		parens = FALSE;
+		t = peek(t);
+		if (t->value == TOKrbracket)
+		{
+		    t = peek(t);
+		}
+		else if (isDeclaration(t, 0, TOKrbracket, &t))
+		{   // It's an associative array declaration
+		    t = peek(t);
+		}
+		else
+		{
+		    // [ expression ]
+		    if (!isExpression(&t))
+			return FALSE;
+		    if (t->value != TOKrbracket)
+			return FALSE;
+		    t = peek(t);
+		}
+		continue;
+#endif
+
+	    case TOKlparen:
+		parens = FALSE;
+		if (!isParameters(&t))
+		    return FALSE;
+		continue;
+
+	    // Valid tokens that follow a declaration
+	    case TOKrparen:
+	    case TOKrbracket:
+	    case TOKassign:
+	    case TOKcomma:
+	    case TOKsemicolon:
+	    case TOKlcurly:
+	    case TOKin:
+		// The !parens is to disallow unnecessary parentheses
+		if (!parens && (endtok == TOKreserved || endtok == t->value))
+		{   *pt = t;
+		    return TRUE;
+		}
+		return FALSE;
+
+	    default:
+		return FALSE;
+	}
+    }
+}
+
+
+int Parser::isParameters(Token **pt)
+{   // This code parallels parseParameters()
+    Token *t = *pt;
+    int tmp;
+
+    //printf("isParameters()\n");
+    if (t->value != TOKlparen)
+	return FALSE;
+
+    t = peek(t);
+    while (1)
+    {
+	switch (t->value)
+	{
+	    case TOKrparen:
+		break;
+
+	    case TOKdotdotdot:
+		t = peek(t);
+		break;
+
+	    case TOKin:
+	    case TOKout:
+	    case TOKinout:
+	    case TOKref:
+	    case TOKlazy:
+		t = peek(t);
+	    default:
+		if (!isBasicType(&t))
+		    return FALSE;
+		tmp = FALSE;
+		if (t->value != TOKdotdotdot &&
+		    !isDeclarator(&t, &tmp, TOKreserved))
+		    return FALSE;
+		if (t->value == TOKassign)
+		{   t = peek(t);
+		    if (!isExpression(&t))
+			return FALSE;
+		}
+		if (t->value == TOKdotdotdot)
+		{
+		    t = peek(t);
+		    break;
+		}
+		if (t->value == TOKcomma)
+		{   t = peek(t);
+		    continue;
+		}
+		break;
+	}
+	break;
+    }
+    if (t->value != TOKrparen)
+	return FALSE;
+    t = peek(t);
+    *pt = t;
+    return TRUE;
+}
+
+int Parser::isExpression(Token **pt)
+{
+    // This is supposed to determine if something is an expression.
+    // What it actually does is scan until a closing right bracket
+    // is found.
+
+    Token *t = *pt;
+    int brnest = 0;
+    int panest = 0;
+
+    for (;; t = peek(t))
+    {
+	switch (t->value)
+	{
+	    case TOKlbracket:
+		brnest++;
+		continue;
+
+	    case TOKrbracket:
+		if (--brnest >= 0)
+		    continue;
+		break;
+
+	    case TOKlparen:
+		panest++;
+		continue;
+
+	    case TOKcomma:
+		if (brnest || panest)
+		    continue;
+		break;
+
+	    case TOKrparen:
+		if (--panest >= 0)
+		    continue;
+		break;
+
+	    case TOKslice:
+		if (brnest)
+		    continue;
+		break;
+
+	    case TOKeof:
+		return FALSE;
+
+	    default:
+		continue;
+	}
+	break;
+    }
+
+    *pt = t;
+    return TRUE;
+}
+
+/**********************************************
+ * Skip over
+ *	instance foo.bar(parameters...)
+ * Output:
+ *	if (pt), *pt is set to the token following the closing )
+ * Returns:
+ *	1	it's valid instance syntax
+ *	0	invalid instance syntax
+ */
+
+int Parser::isTemplateInstance(Token *t, Token **pt)
+{
+    t = peek(t);
+    if (t->value != TOKdot)
+    {
+	if (t->value != TOKidentifier)
+	    goto Lfalse;
+	t = peek(t);
+    }
+    while (t->value == TOKdot)
+    {
+	t = peek(t);
+	if (t->value != TOKidentifier)
+	    goto Lfalse;
+	t = peek(t);
+    }
+    if (t->value != TOKlparen)
+	goto Lfalse;
+
+    // Skip over the template arguments
+    while (1)
+    {
+	while (1)
+	{
+	    t = peek(t);
+	    switch (t->value)
+	    {
+		case TOKlparen:
+		    if (!skipParens(t, &t))
+			goto Lfalse;
+		    continue;
+		case TOKrparen:
+		    break;
+		case TOKcomma:
+		    break;
+		case TOKeof:
+		case TOKsemicolon:
+		    goto Lfalse;
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	if (t->value != TOKcomma)
+	    break;
+    }
+    if (t->value != TOKrparen)
+	goto Lfalse;
+    t = peek(t);
+    if (pt)
+	*pt = t;
+    return 1;
+
+Lfalse:
+    return 0;
+}
+
+/*******************************************
+ * Skip parens, brackets.
+ * Input:
+ *	t is on opening (
+ * Output:
+ *	*pt is set to closing token, which is ')' on success
+ * Returns:
+ *	!=0	successful
+ *	0	some parsing error
+ */
+
+int Parser::skipParens(Token *t, Token **pt)
+{
+    int parens = 0;
+
+    while (1)
+    {
+	switch (t->value)
+	{
+	    case TOKlparen:
+		parens++;
+		break;
+
+	    case TOKrparen:
+		parens--;
+		if (parens < 0)
+		    goto Lfalse;
+		if (parens == 0)
+		    goto Ldone;
+		break;
+
+	    case TOKeof:
+	    case TOKsemicolon:
+		goto Lfalse;
+
+	     default:
+		break;
+	}
+	t = peek(t);
+    }
+
+  Ldone:
+    if (*pt)
+	*pt = t;
+    return 1;
+
+  Lfalse:
+    return 0;
+}
+
+/********************************* Expression Parser ***************************/
+
+Expression *Parser::parsePrimaryExp()
+{   Expression *e;
+    Type *t;
+    Identifier *id;
+    enum TOK save;
+    Loc loc = this->loc;
+
+    //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+    switch (token.value)
+    {
+	case TOKidentifier:
+	    id = token.ident;
+	    nextToken();
+	    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
+	    {	// identifier!(template-argument-list)
+		TemplateInstance *tempinst;
+
+		tempinst = new TemplateInstance(loc, id);
+		nextToken();
+		tempinst->tiargs = parseTemplateArgumentList();
+		e = new ScopeExp(loc, tempinst);
+	    }
+	    else
+		e = new IdentifierExp(loc, id);
+	    break;
+
+	case TOKdollar:
+	    if (!inBrackets)
+		error("'$' is valid only inside [] of index or slice");
+	    e = new DollarExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKdot:
+	    // Signal global scope '.' operator with "" identifier
+	    e = new IdentifierExp(loc, Id::empty);
+	    break;
+
+	case TOKthis:
+	    e = new ThisExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKsuper:
+	    e = new SuperExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKint32v:
+	    e = new IntegerExp(loc, token.int32value, Type::tint32);
+	    nextToken();
+	    break;
+
+	case TOKuns32v:
+	    e = new IntegerExp(loc, token.uns32value, Type::tuns32);
+	    nextToken();
+	    break;
+
+	case TOKint64v:
+	    e = new IntegerExp(loc, token.int64value, Type::tint64);
+	    nextToken();
+	    break;
+
+	case TOKuns64v:
+	    e = new IntegerExp(loc, token.uns64value, Type::tuns64);
+	    nextToken();
+	    break;
+
+	case TOKfloat32v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat32);
+	    nextToken();
+	    break;
+
+	case TOKfloat64v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat64);
+	    nextToken();
+	    break;
+
+	case TOKfloat80v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat80);
+	    nextToken();
+	    break;
+
+	case TOKimaginary32v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary32);
+	    nextToken();
+	    break;
+
+	case TOKimaginary64v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary64);
+	    nextToken();
+	    break;
+
+	case TOKimaginary80v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary80);
+	    nextToken();
+	    break;
+
+	case TOKnull:
+	    e = new NullExp(loc);
+	    nextToken();
+	    break;
+
+#if DMDV2
+	case TOKfile:
+	{   char *s = loc.filename ? loc.filename : mod->ident->toChars();
+	    e = new StringExp(loc, s, strlen(s), 0);
+	    nextToken();
+	    break;
+	}
+
+	case TOKline:
+	    e = new IntegerExp(loc, loc.linnum, Type::tint32);
+	    nextToken();
+	    break;
+#endif
+
+	case TOKtrue:
+	    e = new IntegerExp(loc, 1, Type::tbool);
+	    nextToken();
+	    break;
+
+	case TOKfalse:
+	    e = new IntegerExp(loc, 0, Type::tbool);
+	    nextToken();
+	    break;
+
+	case TOKcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::tchar);
+	    nextToken();
+	    break;
+
+	case TOKwcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::twchar);
+	    nextToken();
+	    break;
+
+	case TOKdcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::tdchar);
+	    nextToken();
+	    break;
+
+	case TOKstring:
+	{   unsigned char *s;
+	    unsigned len;
+	    unsigned char postfix;
+
+	    // cat adjacent strings
+	    s = token.ustring;
+	    len = token.len;
+	    postfix = token.postfix;
+	    while (1)
+	    {
+		nextToken();
+		if (token.value == TOKstring)
+		{   unsigned len1;
+		    unsigned len2;
+		    unsigned char *s2;
+
+		    if (token.postfix)
+		    {	if (token.postfix != postfix)
+			    error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+			postfix = token.postfix;
+		    }
+
+		    len1 = len;
+		    len2 = token.len;
+		    len = len1 + len2;
+		    s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
+		    memcpy(s2, s, len1 * sizeof(unsigned char));
+		    memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
+		    s = s2;
+		}
+		else
+		    break;
+	    }
+	    e = new StringExp(loc, s, len, postfix);
+	    break;
+	}
+
+	CASE_BASIC_TYPES_X(t):
+	    nextToken();
+	L1:
+	    check(TOKdot, t->toChars());
+	    if (token.value != TOKidentifier)
+	    {   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
+		goto Lerr;
+	    }
+	    e = new TypeDotIdExp(loc, t, token.ident);
+	    nextToken();
+	    break;
+
+	case TOKtypeof:
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    t = new TypeTypeof(loc, exp);
+	    e = new TypeExp(loc, t);
+	    break;
+	}
+
+	case TOKtypeid:
+	{   Type *t;
+
+	    nextToken();
+	    check(TOKlparen, "typeid");
+	    t = parseBasicType();
+	    t = parseDeclarator(t,NULL);	// ( type )
+	    check(TOKrparen);
+	    e = new TypeidExp(loc, t);
+	    break;
+	}
+
+#if DMDV2
+	case TOKtraits:
+	{   /* __traits(identifier, args...)
+	     */
+	    Identifier *ident;
+	    Objects *args = NULL;
+
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value != TOKidentifier)
+	    {   error("__traits(identifier, args...) expected");
+		goto Lerr;
+	    }
+	    ident = token.ident;
+	    nextToken();
+	    if (token.value == TOKcomma)
+		args = parseTemplateArgumentList2();	// __traits(identifier, args...)
+	    else
+		check(TOKrparen);		// __traits(identifier)
+
+	    e = new TraitsExp(loc, ident, args);
+	    break;
+	}
+#endif
+
+	case TOKis:
+	{   Type *targ;
+	    Identifier *ident = NULL;
+	    Type *tspec = NULL;
+	    enum TOK tok = TOKreserved;
+	    enum TOK tok2 = TOKreserved;
+	    Loc loc = this->loc;
+
+	    nextToken();
+	    if (token.value == TOKlparen)
+	    {
+		nextToken();
+		targ = parseBasicType();
+		targ = parseDeclarator(targ, &ident);
+		if (token.value == TOKcolon || token.value == TOKequal)
+		{
+		    tok = token.value;
+		    nextToken();
+		    if (tok == TOKequal &&
+			(token.value == TOKtypedef ||
+			 token.value == TOKstruct ||
+			 token.value == TOKunion ||
+			 token.value == TOKclass ||
+			 token.value == TOKsuper ||
+			 token.value == TOKenum ||
+			 token.value == TOKinterface ||
+			 token.value == TOKfunction ||
+			 token.value == TOKdelegate ||
+			 token.value == TOKreturn))
+		    {
+			tok2 = token.value;
+			nextToken();
+		    }
+		    else
+		    {
+			tspec = parseBasicType();
+			tspec = parseDeclarator(tspec, NULL);
+		    }
+		}
+		check(TOKrparen);
+	    }
+	    else
+	    {   error("(type identifier : specialization) expected following is");
+		goto Lerr;
+	    }
+	    e = new IsExp(loc, targ, ident, tok, tspec, tok2);
+	    break;
+	}
+
+	case TOKassert:
+	{   Expression *msg = NULL;
+
+	    nextToken();
+	    check(TOKlparen, "assert");
+	    e = parseAssignExp();
+	    if (token.value == TOKcomma)
+	    {	nextToken();
+		msg = parseAssignExp();
+	    }
+	    check(TOKrparen);
+	    e = new AssertExp(loc, e, msg);
+	    break;
+	}
+
+	case TOKmixin:
+	{
+	    nextToken();
+	    check(TOKlparen, "mixin");
+	    e = parseAssignExp();
+	    check(TOKrparen);
+	    e = new CompileExp(loc, e);
+	    break;
+	}
+
+	case TOKimport:
+	{
+	    nextToken();
+	    check(TOKlparen, "import");
+	    e = parseAssignExp();
+	    check(TOKrparen);
+	    e = new FileExp(loc, e);
+	    break;
+	}
+
+	case TOKlparen:
+	    if (peekPastParen(&token)->value == TOKlcurly)
+	    {	// (arguments) { statements... }
+		save = TOKdelegate;
+		goto case_delegate;
+	    }
+	    // ( expression )
+	    nextToken();
+	    e = parseExpression();
+	    check(loc, TOKrparen);
+	    break;
+
+	case TOKlbracket:
+	{   /* Parse array literals and associative array literals:
+	     *	[ value, value, value ... ]
+	     *	[ key:value, key:value, key:value ... ]
+	     */
+	    Expressions *values = new Expressions();
+	    Expressions *keys = NULL;
+
+	    nextToken();
+	    if (token.value != TOKrbracket)
+	    {
+		while (1)
+		{
+		    Expression *e = parseAssignExp();
+		    if (token.value == TOKcolon && (keys || values->dim == 0))
+		    {	nextToken();
+			if (!keys)
+			    keys = new Expressions();
+			keys->push(e);
+			e = parseAssignExp();
+		    }
+		    else if (keys)
+		    {	error("'key:value' expected for associative array literal");
+			delete keys;
+			keys = NULL;
+		    }
+		    values->push(e);
+		    if (token.value == TOKrbracket)
+			break;
+		    check(TOKcomma);
+		}
+	    }
+	    check(TOKrbracket);
+
+	    if (keys)
+		e = new AssocArrayLiteralExp(loc, keys, values);
+	    else
+		e = new ArrayLiteralExp(loc, values);
+	    break;
+	}
+
+	case TOKlcurly:
+	    // { statements... }
+	    save = TOKdelegate;
+	    goto case_delegate;
+
+	case TOKfunction:
+	case TOKdelegate:
+	    save = token.value;
+	    nextToken();
+	case_delegate:
+	{
+	    /* function type(parameters) { body }
+	     * delegate type(parameters) { body }
+	     */
+	    Arguments *arguments;
+	    int varargs;
+	    FuncLiteralDeclaration *fd;
+	    Type *t;
+
+	    if (token.value == TOKlcurly)
+	    {
+		t = NULL;
+		varargs = 0;
+		arguments = new Arguments();
+	    }
+	    else
+	    {
+		if (token.value == TOKlparen)
+		    t = NULL;
+		else
+		{
+		    t = parseBasicType();
+		    t = parseBasicType2(t);	// function return type
+		}
+		arguments = parseParameters(&varargs);
+	    }
+	    t = new TypeFunction(arguments, t, varargs, linkage);
+	    fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL);
+	    parseContracts(fd);
+	    e = new FuncExp(loc, fd);
+	    break;
+	}
+
+	default:
+	    error("expression expected, not '%s'", token.toChars());
+	Lerr:
+	    // Anything for e, as long as it's not NULL
+	    e = new IntegerExp(loc, 0, Type::tint32);
+	    nextToken();
+	    break;
+    }
+    return parsePostExp(e);
+}
+
+Expression *Parser::parsePostExp(Expression *e)
+{
+    Loc loc;
+
+    while (1)
+    {
+	loc = this->loc;
+	switch (token.value)
+	{
+	    case TOKdot:
+		nextToken();
+		if (token.value == TOKidentifier)
+		{   Identifier *id = token.ident;
+
+		    nextToken();
+		    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
+		    {   // identifier!(template-argument-list)
+			TemplateInstance *tempinst;
+
+			tempinst = new TemplateInstance(loc, id);
+			nextToken();
+			tempinst->tiargs = parseTemplateArgumentList();
+			e = new DotTemplateInstanceExp(loc, e, tempinst);
+		    }
+		    else
+			e = new DotIdExp(loc, e, id);
+		    continue;
+		}
+		else if (token.value == TOKnew)
+		{
+		    e = parseNewExp(e);
+		    continue;
+		}
+		else
+		    error("identifier expected following '.', not '%s'", token.toChars());
+		break;
+
+	    case TOKplusplus:
+		e = new PostExp(TOKplusplus, loc, e);
+		break;
+
+	    case TOKminusminus:
+		e = new PostExp(TOKminusminus, loc, e);
+		break;
+
+	    case TOKlparen:
+		e = new CallExp(loc, e, parseArguments());
+		continue;
+
+	    case TOKlbracket:
+	    {	// array dereferences:
+		//	array[index]
+		//	array[]
+		//	array[lwr .. upr]
+		Expression *index;
+		Expression *upr;
+
+		inBrackets++;
+		nextToken();
+		if (token.value == TOKrbracket)
+		{   // array[]
+		    e = new SliceExp(loc, e, NULL, NULL);
+		    nextToken();
+		}
+		else
+		{
+		    index = parseAssignExp();
+		    if (token.value == TOKslice)
+		    {	// array[lwr .. upr]
+			nextToken();
+			upr = parseAssignExp();
+			e = new SliceExp(loc, e, index, upr);
+		    }
+		    else
+		    {	// array[index, i2, i3, i4, ...]
+			Expressions *arguments = new Expressions();
+			arguments->push(index);
+			if (token.value == TOKcomma)
+			{
+			    nextToken();
+			    while (1)
+			    {   Expression *arg;
+
+				arg = parseAssignExp();
+				arguments->push(arg);
+				if (token.value == TOKrbracket)
+				    break;
+				check(TOKcomma);
+			    }
+			}
+			e = new ArrayExp(loc, e, arguments);
+		    }
+		    check(TOKrbracket);
+		    inBrackets--;
+		}
+		continue;
+	    }
+
+	    default:
+		return e;
+	}
+	nextToken();
+    }
+}
+
+Expression *Parser::parseUnaryExp()
+{   Expression *e;
+    Loc loc = this->loc;
+
+    switch (token.value)
+    {
+	case TOKand:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new AddrExp(loc, e);
+	    break;
+
+	case TOKplusplus:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+	    break;
+
+	case TOKminusminus:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+	    break;
+
+	case TOKmul:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new PtrExp(loc, e);
+	    break;
+
+	case TOKmin:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new NegExp(loc, e);
+	    break;
+
+	case TOKadd:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new UAddExp(loc, e);
+	    break;
+
+	case TOKnot:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new NotExp(loc, e);
+	    break;
+
+	case TOKtilde:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new ComExp(loc, e);
+	    break;
+
+	case TOKdelete:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new DeleteExp(loc, e);
+	    break;
+
+	case TOKnew:
+	    e = parseNewExp(NULL);
+	    break;
+
+	case TOKcast:				// cast(type) expression
+	{   Type *t;
+
+	    nextToken();
+	    check(TOKlparen);
+	    t = parseBasicType();
+	    t = parseDeclarator(t,NULL);	// ( type )
+	    check(TOKrparen);
+
+	    e = parseUnaryExp();
+	    e = new CastExp(loc, e, t);
+	    break;
+	}
+
+	case TOKlparen:
+	{   Token *tk;
+
+	    tk = peek(&token);
+#if CCASTSYNTAX
+	    // If cast
+	    if (isDeclaration(tk, 0, TOKrparen, &tk))
+	    {
+		tk = peek(tk);		// skip over right parenthesis
+		switch (tk->value)
+		{
+		    case TOKdot:
+		    case TOKplusplus:
+		    case TOKminusminus:
+		    case TOKnot:
+		    case TOKdelete:
+		    case TOKnew:
+		    case TOKlparen:
+		    case TOKidentifier:
+		    case TOKthis:
+		    case TOKsuper:
+		    case TOKint32v:
+		    case TOKuns32v:
+		    case TOKint64v:
+		    case TOKuns64v:
+		    case TOKfloat32v:
+		    case TOKfloat64v:
+		    case TOKfloat80v:
+		    case TOKimaginary32v:
+		    case TOKimaginary64v:
+		    case TOKimaginary80v:
+		    case TOKnull:
+		    case TOKtrue:
+		    case TOKfalse:
+		    case TOKcharv:
+		    case TOKwcharv:
+		    case TOKdcharv:
+		    case TOKstring:
+#if 0
+		    case TOKtilde:
+		    case TOKand:
+		    case TOKmul:
+		    case TOKmin:
+		    case TOKadd:
+#endif
+		    case TOKfunction:
+		    case TOKdelegate:
+		    case TOKtypeof:
+#if DMDV2
+		    case TOKfile:
+		    case TOKline:
+#endif
+		    CASE_BASIC_TYPES:		// (type)int.size
+		    {	// (type) una_exp
+			Type *t;
+
+			nextToken();
+			t = parseBasicType();
+			t = parseDeclarator(t,NULL);
+			check(TOKrparen);
+
+			// if .identifier
+			if (token.value == TOKdot)
+			{
+			    nextToken();
+			    if (token.value != TOKidentifier)
+			    {   error("Identifier expected following (type).");
+				return NULL;
+			    }
+			    e = new TypeDotIdExp(loc, t, token.ident);
+			    nextToken();
+			    e = parsePostExp(e);
+			}
+			else
+			{
+			    e = parseUnaryExp();
+			    e = new CastExp(loc, e, t);
+			    error("C style cast illegal, use %s", e->toChars());
+			}
+			return e;
+		    }
+		}
+	    }
+#endif
+	    e = parsePrimaryExp();
+	    break;
+	}
+	default:
+	    e = parsePrimaryExp();
+	    break;
+    }
+    assert(e);
+    return e;
+}
+
+Expression *Parser::parseMulExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseUnaryExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
+	    case TOKdiv:   nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
+	    case TOKmod:  nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAddExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseMulExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
+	    case TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
+	    case TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseShiftExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAddExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
+	    case TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
+	    case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseRelExp()
+{   Expression *e;
+    Expression *e2;
+    enum TOK op;
+    Loc loc = this->loc;
+
+    e = parseShiftExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKlt:
+	    case TOKle:
+	    case TOKgt:
+	    case TOKge:
+	    case TOKunord:
+	    case TOKlg:
+	    case TOKleg:
+	    case TOKule:
+	    case TOKul:
+	    case TOKuge:
+	    case TOKug:
+	    case TOKue:
+		op = token.value;
+		nextToken();
+		e2 = parseShiftExp();
+		e = new CmpExp(op, loc, e, e2);
+		continue;
+
+	    case TOKin:
+		nextToken();
+		e2 = parseShiftExp();
+		e = new InExp(loc, e, e2);
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseEqualExp()
+{   Expression *e;
+    Expression *e2;
+    Token *t;
+    Loc loc = this->loc;
+
+    e = parseRelExp();
+    while (1)
+    {	enum TOK value = token.value;
+
+	switch (value)
+	{
+	    case TOKequal:
+	    case TOKnotequal:
+		nextToken();
+		e2 = parseRelExp();
+		e = new EqualExp(value, loc, e, e2);
+		continue;
+
+	    case TOKidentity:
+		error("'===' is no longer legal, use 'is' instead");
+		goto L1;
+
+	    case TOKnotidentity:
+		error("'!==' is no longer legal, use '!is' instead");
+		goto L1;
+
+	    case TOKis:
+		value = TOKidentity;
+		goto L1;
+
+	    case TOKnot:
+		// Attempt to identify '!is'
+		t = peek(&token);
+		if (t->value != TOKis)
+		    break;
+		nextToken();
+		value = TOKnotidentity;
+		goto L1;
+
+	    L1:
+		nextToken();
+		e2 = parseRelExp();
+		e = new IdentityExp(value, loc, e, e2);
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseCmpExp()
+{   Expression *e;
+    Expression *e2;
+    Token *t;
+    Loc loc = this->loc;
+
+    e = parseShiftExp();
+    enum TOK op = token.value;
+
+    switch (op)
+    {
+	case TOKequal:
+	case TOKnotequal:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new EqualExp(op, loc, e, e2);
+	    break;
+
+	case TOKis:
+	    op = TOKidentity;
+	    goto L1;
+
+	case TOKnot:
+	    // Attempt to identify '!is'
+	    t = peek(&token);
+	    if (t->value != TOKis)
+		break;
+	    nextToken();
+	    op = TOKnotidentity;
+	    goto L1;
+
+	L1:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new IdentityExp(op, loc, e, e2);
+	    break;
+
+	case TOKlt:
+	case TOKle:
+	case TOKgt:
+	case TOKge:
+	case TOKunord:
+	case TOKlg:
+	case TOKleg:
+	case TOKule:
+	case TOKul:
+	case TOKuge:
+	case TOKug:
+	case TOKue:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new CmpExp(op, loc, e, e2);
+	    break;
+
+	case TOKin:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new InExp(loc, e, e2);
+	    break;
+
+	default:
+	    break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAndExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    if (global.params.Dversion == 1)
+    {
+	e = parseEqualExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseEqualExp();
+	    e = new AndExp(loc,e,e2);
+	    loc = this->loc;
+	}
+    }
+    else
+    {
+	e = parseCmpExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseCmpExp();
+	    e = new AndExp(loc,e,e2);
+	    loc = this->loc;
+	}
+    }
+    return e;
+}
+
+Expression *Parser::parseXorExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAndExp();
+    while (token.value == TOKxor)
+    {
+	nextToken();
+	e2 = parseAndExp();
+	e = new XorExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseXorExp();
+    while (token.value == TOKor)
+    {
+	nextToken();
+	e2 = parseXorExp();
+	e = new OrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAndAndExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseOrExp();
+    while (token.value == TOKandand)
+    {
+	nextToken();
+	e2 = parseOrExp();
+	e = new AndAndExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrOrExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAndAndExp();
+    while (token.value == TOKoror)
+    {
+	nextToken();
+	e2 = parseAndAndExp();
+	e = new OrOrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseCondExp()
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseOrOrExp();
+    if (token.value == TOKquestion)
+    {
+	nextToken();
+	e1 = parseExpression();
+	check(TOKcolon);
+	e2 = parseCondExp();
+	e = new CondExp(loc, e, e1, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAssignExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc;
+
+    e = parseCondExp();
+    while (1)
+    {
+	loc = this->loc;
+	switch (token.value)
+	{
+#define X(tok,ector) \
+	    case tok:  nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
+
+	    X(TOKassign,    AssignExp);
+	    X(TOKaddass,    AddAssignExp);
+	    X(TOKminass,    MinAssignExp);
+	    X(TOKmulass,    MulAssignExp);
+	    X(TOKdivass,    DivAssignExp);
+	    X(TOKmodass,    ModAssignExp);
+	    X(TOKandass,    AndAssignExp);
+	    X(TOKorass,     OrAssignExp);
+	    X(TOKxorass,    XorAssignExp);
+	    X(TOKshlass,    ShlAssignExp);
+	    X(TOKshrass,    ShrAssignExp);
+	    X(TOKushrass,   UshrAssignExp);
+	    X(TOKcatass,    CatAssignExp);
+
+#undef X
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseExpression()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
+    e = parseAssignExp();
+    while (token.value == TOKcomma)
+    {
+	nextToken();
+	e2 = parseAssignExp();
+	e = new CommaExp(loc, e, e2);
+	loc = this->loc;
+    }
+    return e;
+}
+
+
+/*************************
+ * Collect argument list.
+ * Assume current token is '(' or '['.
+ */
+
+Expressions *Parser::parseArguments()
+{   // function call
+    Expressions *arguments;
+    Expression *arg;
+    enum TOK endtok;
+
+    arguments = new Expressions();
+    if (token.value == TOKlbracket)
+	endtok = TOKrbracket;
+    else
+	endtok = TOKrparen;
+
+    {
+	nextToken();
+	if (token.value != endtok)
+	{
+	    while (1)
+	    {
+		arg = parseAssignExp();
+		arguments->push(arg);
+		if (token.value == endtok)
+		    break;
+		check(TOKcomma);
+	    }
+	}
+	check(endtok);
+    }
+    return arguments;
+}
+
+/*******************************************
+ */
+
+Expression *Parser::parseNewExp(Expression *thisexp)
+{   Type *t;
+    Expressions *newargs;
+    Expressions *arguments = NULL;
+    Expression *e;
+    Loc loc = this->loc;
+
+    nextToken();
+    newargs = NULL;
+    if (token.value == TOKlparen)
+    {
+	newargs = parseArguments();
+    }
+
+    // An anonymous nested class starts with "class"
+    if (token.value == TOKclass)
+    {
+	nextToken();
+	if (token.value == TOKlparen)
+	    arguments = parseArguments();
+
+	BaseClasses *baseclasses = NULL;
+	if (token.value != TOKlcurly)
+	    baseclasses = parseBaseClasses();
+
+	Identifier *id = NULL;
+	ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
+
+	if (token.value != TOKlcurly)
+	{   error("{ members } expected for anonymous class");
+	    cd->members = NULL;
+	}
+	else
+	{
+	    nextToken();
+	    Array *decl = parseDeclDefs(0);
+	    if (token.value != TOKrcurly)
+		error("class member expected");
+	    nextToken();
+	    cd->members = decl;
+	}
+
+	e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+
+	return e;
+    }
+
+#if LTORARRAYDECL
+    t = parseBasicType();
+    t = parseBasicType2(t);
+    if (t->ty == Taarray)
+    {
+	Type *index = ((TypeAArray *)t)->index;
+
+	Expression *e = index->toExpression();
+	if (e)
+	{   arguments = new Expressions();
+	    arguments->push(e);
+	    t = new TypeDArray(t->next);
+	}
+	else
+	{
+	    error("need size of rightmost array, not type %s", index->toChars());
+	    return new NullExp(loc);
+	}
+    }
+    else if (t->ty == Tsarray)
+    {
+	TypeSArray *tsa = (TypeSArray *)t;
+	Expression *e = tsa->dim;
+
+	arguments = new Expressions();
+	arguments->push(e);
+	t = new TypeDArray(t->next);
+    }
+    else if (token.value == TOKlparen)
+    {
+	arguments = parseArguments();
+    }
+#else
+    t = parseBasicType();
+    while (token.value == TOKmul)
+    {   t = new TypePointer(t);
+	nextToken();
+    }
+    if (token.value == TOKlbracket)
+    {
+	Expression *e;
+
+	nextToken();
+	e = parseAssignExp();
+	arguments = new Array();
+	arguments->push(e);
+	check(TOKrbracket);
+	t = parseDeclarator(t, NULL);
+	t = new TypeDArray(t);
+    }
+    else if (token.value == TOKlparen)
+	arguments = parseArguments();
+#endif
+    e = new NewExp(loc, thisexp, newargs, t, arguments);
+    return e;
+}
+
+/**********************************************
+ */
+
+void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
+{
+    s->addComment(combineComments(blockComment, token.lineComment));
+}
+
+
+/********************************* ***************************/
+
--- a/dmd/parse.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/parse.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -20,6 +20,7 @@
 #include "enum.h"
 
 struct Type;
+struct TypeQualified;
 struct Expression;
 struct Declaration;
 struct Statement;
@@ -27,6 +28,7 @@
 struct Initializer;
 struct FuncDeclaration;
 struct CtorDeclaration;
+struct PostBlitDeclaration;
 struct DtorDeclaration;
 struct StaticCtorDeclaration;
 struct StaticDtorDeclaration;
--- a/dmd/root.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/root.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,1836 +1,1855 @@
-
-// Copyright (c) 1999-2006 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-
-#if _MSC_VER ||__MINGW32__
-#include <malloc.h>
-#endif
-
-#if _WIN32
-#include <windows.h>
-#include <direct.h>
-#endif
-
-#if linux
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <utime.h>
-#endif
-
-#include "port.h"
-#include "root.h"
-#include "dchar.h"
-#include "mem.h"
-#include "mars.h"
-
-#if 0 //__SC__ //def DEBUG
-extern "C" void __cdecl _assert(void *e, void *f, unsigned line)
-{
-    printf("Assert('%s','%s',%d)\n",e,f,line);
-    fflush(stdout);
-    *(char *)0 = 0;
-}
-#endif
-
-/*************************************
- * Convert wchar string to ascii string.
- */
-
-char *wchar2ascii(wchar_t *us)
-{
-    return wchar2ascii(us, wcslen(us));
-}
-
-char *wchar2ascii(wchar_t *us, unsigned len)
-{
-    unsigned i;
-    char *p;
-
-    p = (char *)mem.malloc(len + 1);
-    for (i = 0; i <= len; i++)
-	p[i] = (char) us[i];
-    return p;
-}
-
-int wcharIsAscii(wchar_t *us)
-{
-    return wcharIsAscii(us, wcslen(us));
-}
-
-int wcharIsAscii(wchar_t *us, unsigned len)
-{
-    unsigned i;
-
-    for (i = 0; i <= len; i++)
-    {
-	if (us[i] & ~0xFF)	// if high bits set
-	    return 0;		// it's not ascii
-    }
-    return 1;
-}
-
-
-/***********************************
- * Compare length-prefixed strings (bstr).
- */
-
-int bstrcmp(unsigned char *b1, unsigned char *b2)
-{
-    return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1;
-}
-
-/***************************************
- * Convert bstr into a malloc'd string.
- */
-
-char *bstr2str(unsigned char *b)
-{
-    char *s;
-    unsigned len;
-
-    len = *b;
-    s = (char *) mem.malloc(len + 1);
-    s[len] = 0;
-    return (char *)memcpy(s,b + 1,len);
-}
-
-/**************************************
- * Print error message and exit.
- */
-
-void error(const char *format, ...)
-{
-    va_list ap;
-
-    va_start(ap, format);
-    printf("Error: ");
-    vprintf(format, ap);
-    va_end( ap );
-    printf("\n");
-    fflush(stdout);
-
-    exit(EXIT_FAILURE);
-}
-
-#if M_UNICODE
-void error(const dchar *format, ...)
-{
-    va_list ap;
-
-    va_start(ap, format);
-    printf("Error: ");
-    vwprintf(format, ap);
-    va_end( ap );
-    printf("\n");
-    fflush(stdout);
-
-    exit(EXIT_FAILURE);
-}
-#endif
-
-void error_mem()
-{
-    error("out of memory");
-}
-
-/**************************************
- * Print warning message.
- */
-
-void warning(const char *format, ...)
-{
-    va_list ap;
-
-    va_start(ap, format);
-    printf("Warning: ");
-    vprintf(format, ap);
-    va_end( ap );
-    printf("\n");
-    fflush(stdout);
-}
-
-/****************************** Object ********************************/
-
-int Object::equals(Object *o)
-{
-    return o == this;
-}
-
-hash_t Object::hashCode()
-{
-    return (hash_t) this;
-}
-
-int Object::compare(Object *obj)
-{
-    return this - obj;
-}
-
-void Object::print()
-{
-    printf("%s %p\n", toChars(), this);
-}
-
-char *Object::toChars()
-{
-    return "Object";
-}
-
-dchar *Object::toDchars()
-{
-#if M_UNICODE
-    return L"Object";
-#else
-    return toChars();
-#endif
-}
-
-int Object::dyncast()
-{
-    return 0;
-}
-
-void Object::toBuffer(OutBuffer *b)
-{
-    b->writestring("Object");
-}
-
-void Object::mark()
-{
-}
-
-/****************************** String ********************************/
-
-String::String(char *str, int ref)
-{
-    this->str = ref ? str : mem.strdup(str);
-    this->ref = ref;
-}
-
-String::~String()
-{
-    mem.free(str);
-}
-
-void String::mark()
-{
-    mem.mark(str);
-}
-
-hash_t String::calcHash(const char *str, size_t len)
-{
-    hash_t hash = 0;
-
-    for (;;)
-    {
-	switch (len)
-	{
-	    case 0:
-		return hash;
-
-	    case 1:
-		hash *= 37;
-		hash += *(uint8_t *)str;
-		return hash;
-
-	    case 2:
-		hash *= 37;
-		hash += *(uint16_t *)str;
-		return hash;
-
-	    case 3:
-		hash *= 37;
-		hash += (*(uint16_t *)str << 8) +
-			((uint8_t *)str)[2];
-		return hash;
-
-	    default:
-		hash *= 37;
-		hash += *(uint32_t *)str;
-		str += 4;
-		len -= 4;
-		break;
-	}
-    }
-}
-
-hash_t String::calcHash(const char *str)
-{
-    return calcHash(str, strlen(str));
-}
-
-hash_t String::hashCode()
-{
-    return calcHash(str, strlen(str));
-}
-
-unsigned String::len()
-{
-    return strlen(str);
-}
-
-int String::equals(Object *obj)
-{
-    return strcmp(str,((String *)obj)->str) == 0;
-}
-
-int String::compare(Object *obj)
-{
-    return strcmp(str,((String *)obj)->str);
-}
-
-char *String::toChars()
-{
-    return str;
-}
-
-void String::print()
-{
-    printf("String '%s'\n",str);
-}
-
-
-/****************************** FileName ********************************/
-
-FileName::FileName(char *str, int ref)
-    : String(str,ref)
-{
-}
-
-char *FileName::combine(char *path, char *name)
-{   char *f;
-    size_t pathlen;
-    size_t namelen;
-
-    if (!path || !*path)
-	return name;
-    pathlen = strlen(path);
-    namelen = strlen(name);
-    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
-    memcpy(f, path, pathlen);
-#if linux
-    if (path[pathlen - 1] != '/')
-    {	f[pathlen] = '/';
-	pathlen++;
-    }
-#endif
-#if _WIN32
-    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
-    {	f[pathlen] = '\\';
-	pathlen++;
-    }
-#endif
-    memcpy(f + pathlen, name, namelen + 1);
-    return f;
-}
-
-FileName::FileName(char *path, char *name)
-    : String(combine(path,name),1)
-{
-}
-
-// Split a path into an Array of paths
-Array *FileName::splitPath(const char *path)
-{
-    char c = 0;				// unnecessary initializer is for VC /W4
-    const char *p;
-    OutBuffer buf;
-    Array *array;
-
-    array = new Array();
-    if (path)
-    {
-	p = path;
-	do
-	{   char instring = 0;
-
-	    while (isspace(*p))		// skip leading whitespace
-		p++;
-	    buf.reserve(strlen(p) + 1);	// guess size of path
-	    for (; ; p++)
-	    {
-		c = *p;
-		switch (c)
-		{
-		    case '"':
-			instring ^= 1;	// toggle inside/outside of string
-			continue;
-
-#if MACINTOSH
-		    case ',':
-#endif
-#if _WIN32
-		    case ';':
-#endif
-#if linux
-		    case ':':
-#endif
-			p++;
-			break;		// note that ; cannot appear as part
-					// of a path, quotes won't protect it
-
-		    case 0x1A:		// ^Z means end of file
-		    case 0:
-			break;
-
-		    case '\r':
-			continue;	// ignore carriage returns
-
-#if linux
-		    case '~':
-			buf.writestring(getenv("HOME"));
-			continue;
-#endif
-
-		    case ' ':
-		    case '\t':		// tabs in filenames?
-			if (!instring)	// if not in string
-			    break;	// treat as end of path
-		    default:
-			buf.writeByte(c);
-			continue;
-		}
-		break;
-	    }
-	    if (buf.offset)		// if path is not empty
-	    {
-		buf.writeByte(0);	// to asciiz
-		array->push(buf.extractData());
-	    }
-	} while (c);
-    }
-    return array;
-}
-
-hash_t FileName::hashCode()
-{
-#if _WIN32
-    // We need a different hashCode because it must be case-insensitive
-    size_t len = strlen(str);
-    hash_t hash = 0;
-    unsigned char *s = (unsigned char *)str;
-
-    for (;;)
-    {
-	switch (len)
-	{
-	    case 0:
-		return hash;
-
-	    case 1:
-		hash *= 37;
-		hash += *(uint8_t *)s | 0x20;
-		return hash;
-
-	    case 2:
-		hash *= 37;
-		hash += *(uint16_t *)s | 0x2020;
-		return hash;
-
-	    case 3:
-		hash *= 37;
-		hash += ((*(uint16_t *)s << 8) +
-			 ((uint8_t *)s)[2]) | 0x202020;
-		break;
-
-	    default:
-		hash *= 37;
-		hash += *(uint32_t *)s | 0x20202020;
-		s += 4;
-		len -= 4;
-		break;
-	}
-    }
-#else
-    // darwin HFS is case insensitive, though...
-    return String::hashCode();
-#endif
-}
-
-int FileName::compare(Object *obj)
-{
-#if _WIN32
-    return stricmp(str,((FileName *)obj)->str);
-#else
-    return String::compare(obj);
-#endif
-}
-
-int FileName::equals(Object *obj)
-{
-#if _WIN32
-    return stricmp(str,((FileName *)obj)->str) == 0;
-#else
-    return String::equals(obj);
-#endif
-}
-
-/************************************
- * Return !=0 if absolute path name.
- */
-
-int FileName::absolute(const char *name)
-{
-#if _WIN32
-    return (*name == '\\') ||
-	   (*name == '/')  ||
-	   (*name && name[1] == ':');
-#endif
-#if linux
-    return (*name == '/');
-#endif
-}
-
-/********************************
- * Return filename extension (read-only).
- * If there isn't one, return NULL.
- */
-
-char *FileName::ext(const char *str)
-{
-    char *e;
-    size_t len = strlen(str);
-
-    e = (char *)str + len;
-    for (;;)
-    {
-	switch (*e)
-	{   case '.':
-		return e + 1;
-#if linux
-	    case '/':
-	        break;
-#endif
-#if _WIN32
-	    case '\\':
-	    case ':':
-		break;
-#endif
-	    default:
-		if (e == str)
-		    break;
-		e--;
-		continue;
-	}
-	return NULL;
-    }
-}
-
-char *FileName::ext()
-{
-    return ext(str);
-}
-
-/********************************
- * Return filename name excluding path (read-only).
- */
-
-char *FileName::name(const char *str)
-{
-    char *e;
-    size_t len = strlen(str);
-
-    e = (char *)str + len;
-    for (;;)
-    {
-	switch (*e)
-	{
-#if linux
-	    case '/':
-	       return e + 1;
-#endif
-#if _WIN32
-	    case '\\':
-	    case ':':
-		return e + 1;
-#endif
-	    default:
-		if (e == str)
-		    break;
-		e--;
-		continue;
-	}
-	return e;
-    }
-}
-
-char *FileName::name()
-{
-    return name(str);
-}
-
-/**************************************
- * Return path portion of str.
- * Path will does not include trailing path separator.
- */
-
-char *FileName::path(const char *str)
-{
-    char *n = name(str);
-    char *path;
-    size_t pathlen;
-
-    if (n > str)
-    {
-#if linux
-	if (n[-1] == '/')
-	    n--;
-#endif
-#if _WIN32
-	if (n[-1] == '\\')
-	    n--;
-#endif
-    }
-    pathlen = n - str;
-    path = (char *)mem.malloc(pathlen + 1);
-    memcpy(path, str, pathlen);
-    path[pathlen] = 0;
-    return path;
-}
-
-/**************************************
- * Replace filename portion of path.
- */
-
-char *FileName::replaceName(char *path, char *name)
-{   char *f;
-    char *n;
-    size_t pathlen;
-    size_t namelen;
-
-    if (absolute(name))
-	return name;
-
-    n = FileName::name(path);
-    if (n == path)
-	return name;
-    pathlen = n - path;
-    namelen = strlen(name);
-    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
-    memcpy(f, path, pathlen);
-#if linux
-    if (path[pathlen - 1] != '/')
-    {	f[pathlen] = '/';
-	pathlen++;
-    }
-#endif
-#if _WIN32
-    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
-    {	f[pathlen] = '\\';
-	pathlen++;
-    }
-#endif
-    memcpy(f + pathlen, name, namelen + 1);
-    return f;
-}
-
-/***************************
- */
-
-FileName *FileName::defaultExt(const char *name, const char *ext)
-{
-    char *e;
-    char *s;
-    size_t len;
-    size_t extlen;
-
-    e = FileName::ext(name);
-    if (e)				// if already has an extension
-	return new FileName((char *)name, 0);
-
-    len = strlen(name);
-    extlen = strlen(ext);
-    s = (char *)alloca(len + 1 + extlen + 1);
-    memcpy(s,name,len);
-    s[len] = '.';
-    memcpy(s + len + 1, ext, extlen + 1);
-    return new FileName(s, 0);
-}
-
-/***************************
- */
-
-FileName *FileName::forceExt(const char *name, const char *ext)
-{
-    char *e;
-    char *s;
-    size_t len;
-    size_t extlen;
-
-    e = FileName::ext(name);
-    if (e)				// if already has an extension
-    {
-	len = e - name;
-	extlen = strlen(ext);
-
-	s = (char *)alloca(len + extlen + 1);
-	memcpy(s,name,len);
-	memcpy(s + len, ext, extlen + 1);
-	return new FileName(s, 0);
-    }
-    else
-	return defaultExt(name, ext);	// doesn't have one
-}
-
-/******************************
- * Return !=0 if extensions match.
- */
-
-int FileName::equalsExt(const char *ext)
-{   const char *e;
-
-    e = FileName::ext();
-    if (!e && !ext)
-	return 1;
-    if (!e || !ext)
-	return 0;
-#if linux
-    return strcmp(e,ext) == 0;
-#endif
-#if _WIN32
-    return stricmp(e,ext) == 0;
-#endif
-}
-
-/*************************************
- * Copy file from this to to.
- */
-
-void FileName::CopyTo(FileName *to)
-{
-    File file(this);
-
-#if _WIN32
-    file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));	// keep same file time
-#endif
-#if linux
-    file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time
-#endif
-    file.readv();
-    file.name = to;
-    file.writev();
-}
-
-/*************************************
- * Search Path for file.
- * Input:
- *	cwd	if !=0, search current directory before searching path
- */
-
-char *FileName::searchPath(Array *path, char *name, int cwd)
-{
-    if (absolute(name))
-    {
-	return exists(name) ? name : NULL;
-    }
-    if (cwd)
-    {
-	if (exists(name))
-	    return name;
-    }
-    if (path)
-    {	unsigned i;
-
-	for (i = 0; i < path->dim; i++)
-	{
-	    char *p = (char *)path->data[i];
-	    char *n = combine(p, name);
-
-	    if (exists(n))
-		return n;
-	}
-    }
-    return NULL;
-}
-
-int FileName::exists(const char *name)
-{
-#if linux
-    struct stat st;
-
-    if (stat(name, &st) < 0)
-	return 0;
-    if (S_ISDIR(st.st_mode))
-	return 2;
-    return 1;
-#endif
-#if _WIN32
-    DWORD dw;
-    int result;
-
-    dw = GetFileAttributesA(name);
-    if (dw == -1L)
-	result = 0;
-    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
-	result = 2;
-    else
-	result = 1;
-    return result;
-#endif
-}
-
-void FileName::ensurePathExists(const char *path)
-{
-    //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
-    if (path && *path)
-    {
-	if (!exists(path))
-	{
-	    char *p = FileName::path(path);
-	    if (*p)
-	    {
-#if _WIN32
-		size_t len = strlen(p);
-		if (len > 2 && p[-1] == ':')
-		{   mem.free(p);
-		    return;
-		}
-#endif
-		ensurePathExists(p);
-		mem.free(p);
-	    }
-#if _WIN32
-	    if (path[strlen(path) - 1] != '\\')
-#endif
-#if linux
-	    if (path[strlen(path) - 1] != '\\')
-#endif
-	    {
-		//printf("mkdir(%s)\n", path);
-#if _WIN32
-		if (mkdir(path))
-#endif
-#if linux
-		if (mkdir(path, 0777))
-#endif
-		    error("cannot create directory %s", path);
-	    }
-	}
-    }
-}
-
-/****************************** File ********************************/
-
-File::File(FileName *n)
-{
-    ref = 0;
-    buffer = NULL;
-    len = 0;
-    touchtime = NULL;
-    name = n;
-}
-
-File::File(char *n)
-{
-    ref = 0;
-    buffer = NULL;
-    len = 0;
-    touchtime = NULL;
-    name = new FileName(n, 0);
-}
-
-File::~File()
-{
-    if (buffer)
-    {
-	if (ref == 0)
-	    mem.free(buffer);
-#if _WIN32
-	else if (ref == 2)
-	    UnmapViewOfFile(buffer);
-#endif
-    }
-    if (touchtime)
-	mem.free(touchtime);
-}
-
-void File::mark()
-{
-    mem.mark(buffer);
-    mem.mark(touchtime);
-    mem.mark(name);
-}
-
-/*************************************
- */
-
-int File::read()
-{
-#if linux
-    off_t size;
-    ssize_t numread;
-    int fd;
-    struct stat buf;
-    int result = 0;
-    char *name;
-
-    name = this->name->toChars();
-    //printf("File::read('%s')\n",name);
-    fd = open(name, O_RDONLY);
-    if (fd == -1)
-    {	result = errno;
-	//printf("\topen error, errno = %d\n",errno);
-	goto err1;
-    }
-
-    if (!ref)
-	mem.free(buffer);
-    ref = 0;       // we own the buffer now
-
-    //printf("\tfile opened\n");
-    if (fstat(fd, &buf))
-    {
-	printf("\tfstat error, errno = %d\n",errno);
-        goto err2;
-    }
-    size = buf.st_size;
-    buffer = (unsigned char *) mem.malloc(size + 2);
-    if (!buffer)
-    {
-	printf("\tmalloc error, errno = %d\n",errno);
-	goto err2;
-    }
-
-    numread = ::read(fd, buffer, size);
-    if (numread != size)
-    {
-	printf("\tread error, errno = %d\n",errno);
-	goto err2;
-    }
-
-    if (touchtime)
-        memcpy(touchtime, &buf, sizeof(buf));
-
-    if (close(fd) == -1)
-    {
-	printf("\tclose error, errno = %d\n",errno);
-	goto err;
-    }
-
-    len = size;
-
-    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
-    buffer[size] = 0;		// ^Z is obsolete, use 0
-    buffer[size + 1] = 0;
-    return 0;
-
-err2:
-    close(fd);
-err:
-    mem.free(buffer);
-    buffer = NULL;
-    len = 0;
-
-err1:
-    result = 1;
-    return result;
-#endif
-#if _WIN32
-    DWORD size;
-    DWORD numread;
-    HANDLE h;
-    int result = 0;
-    char *name;
-
-    name = this->name->toChars();
-    h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
-	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0);
-    if (h == INVALID_HANDLE_VALUE)
-	goto err1;
-
-    if (!ref)
-	mem.free(buffer);
-    ref = 0;
-
-    size = GetFileSize(h,NULL);
-    buffer = (unsigned char *) mem.malloc(size + 2);
-    if (!buffer)
-	goto err2;
-
-    if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
-	goto err2;
-
-    if (numread != size)
-	goto err2;
-
-    if (touchtime)
-    {
-	if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime))
-	    goto err2;
-    }
-
-    if (!CloseHandle(h))
-	goto err;
-
-    len = size;
-
-    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
-    buffer[size] = 0;		// ^Z is obsolete, use 0
-    buffer[size + 1] = 0;
-    return 0;
-
-err2:
-    CloseHandle(h);
-err:
-    mem.free(buffer);
-    buffer = NULL;
-    len = 0;
-
-err1:
-    result = 1;
-    return result;
-#endif
-}
-
-/*****************************
- * Read a file with memory mapped file I/O.
- */
-
-int File::mmread()
-{
-#if linux
-    return read();
-#endif
-#if _WIN32
-    HANDLE hFile;
-    HANDLE hFileMap;
-    DWORD size;
-    char *name;
-
-    name = this->name->toChars();
-    hFile = CreateFile(name, GENERIC_READ,
-			FILE_SHARE_READ, NULL,
-			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (hFile == INVALID_HANDLE_VALUE)
-	goto Lerr;
-    size = GetFileSize(hFile, NULL);
-    //printf(" file created, size %d\n", size);
-
-    hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL);
-    if (CloseHandle(hFile) != TRUE)
-	goto Lerr;
-
-    if (hFileMap == NULL)
-	goto Lerr;
-
-    //printf(" mapping created\n");
-
-    if (!ref)
-	mem.free(buffer);
-    ref = 2;
-    buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL);
-    if (CloseHandle(hFileMap) != TRUE)
-	goto Lerr;
-    if (buffer == NULL)			// mapping view failed
-	goto Lerr;
-
-    len = size;
-    //printf(" buffer = %p\n", buffer);
-
-    return 0;
-
-Lerr:
-    return GetLastError();			// failure
-#endif
-}
-
-/*********************************************
- * Write a file.
- * Returns:
- *	0	success
- */
-
-int File::write()
-{
-#if linux
-    int fd;
-    ssize_t numwritten;
-    char *name;
-
-    name = this->name->toChars();
-    fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0660);
-    if (fd == -1)
-	goto err;
-
-    numwritten = ::write(fd, buffer, len);
-    if (len != numwritten)
-	goto err2;
-    
-    if (close(fd) == -1)
-	goto err;
-
-    if (touchtime)
-    {   struct utimbuf ubuf;
-
-        ubuf.actime = ((struct stat *)touchtime)->st_atime;
-        ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
-	if (utime(name, &ubuf))
-	    goto err;
-    }
-    return 0;
-
-err2:
-    close(fd);
-    ::remove(name);
-err:
-    return 1;
-#endif
-#if _WIN32
-    HANDLE h;
-    DWORD numwritten;
-    char *name;
-
-    name = this->name->toChars();
-    h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
-	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
-    if (h == INVALID_HANDLE_VALUE)
-	goto err;
-
-    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
-	goto err2;
-
-    if (len != numwritten)
-	goto err2;
-    
-    if (touchtime) {
-        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
-    }
-    if (!CloseHandle(h))
-	goto err;
-    return 0;
-
-err2:
-    CloseHandle(h);
-    DeleteFileA(name);
-err:
-    return 1;
-#endif
-}
-
-/*********************************************
- * Append to a file.
- * Returns:
- *	0	success
- */
-
-int File::append()
-{
-#if linux
-    return 1;
-#endif
-#if _WIN32
-    HANDLE h;
-    DWORD numwritten;
-    char *name;
-
-    name = this->name->toChars();
-    h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
-	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
-    if (h == INVALID_HANDLE_VALUE)
-	goto err;
-
-#if 1
-    SetFilePointer(h, 0, NULL, FILE_END);
-#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition
-    if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
-	goto err;
-#endif
-
-    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
-	goto err2;
-
-    if (len != numwritten)
-	goto err2;
-    
-    if (touchtime) {
-        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
-    }
-    if (!CloseHandle(h))
-	goto err;
-    return 0;
-
-err2:
-    CloseHandle(h);
-err:
-    return 1;
-#endif
-}
-
-/**************************************
- */
-
-void File::readv()
-{
-    if (read())
-	error("Error reading file '%s'\n",name->toChars());
-}
-
-/**************************************
- */
-
-void File::mmreadv()
-{
-    if (mmread())
-	readv();
-}
-
-void File::writev()
-{
-    if (write())
-	error("Error writing file '%s'\n",name->toChars());
-}
-
-void File::appendv()
-{
-    if (write())
-	error("Error appending to file '%s'\n",name->toChars());
-}
-
-/*******************************************
- * Return !=0 if file exists.
- *	0:	file doesn't exist
- *	1:	normal file
- *	2:	directory
- */
-
-int File::exists()
-{
-#if linux
-    return 0;
-#endif
-#if _WIN32
-    DWORD dw;
-    int result;
-    char *name;
-
-    name = this->name->toChars();
-    if (touchtime)
-	dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes;
-    else
-	dw = GetFileAttributesA(name);
-    if (dw == -1L)
-	result = 0;
-    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
-	result = 2;
-    else
-	result = 1;
-    return result;
-#endif
-}
-
-void File::remove()
-{
-#if linux
-    ::remove(this->name->toChars());
-#endif
-#if _WIN32
-    DeleteFileA(this->name->toChars());
-#endif
-}
-
-Array *File::match(char *n)
-{
-    return match(new FileName(n, 0));
-}
-
-Array *File::match(FileName *n)
-{
-#if linux
-    return NULL;
-#endif
-#if _WIN32
-    HANDLE h;
-    WIN32_FIND_DATAA fileinfo;
-    Array *a;
-    char *c;
-    char *name;
-
-    a = new Array();
-    c = n->toChars();
-    name = n->name();
-    h = FindFirstFileA(c,&fileinfo);
-    if (h != INVALID_HANDLE_VALUE)
-    {
-	do
-	{
-	    // Glue path together with name
-	    char *fn;
-	    File *f;
-
-	    fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
-	    memcpy(fn, c, name - c);
-	    strcpy(fn + (name - c), fileinfo.cFileName);
-	    f = new File(fn);
-	    f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
-	    memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
-	    a->push(f);
-	} while (FindNextFileA(h,&fileinfo) != FALSE);
-	FindClose(h);
-    }
-    return a;
-#endif
-}
-
-int File::compareTime(File *f)
-{
-#if linux
-    return 0;
-#endif
-#if _WIN32
-    if (!touchtime)
-	stat();
-    if (!f->touchtime)
-	f->stat();
-    return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime);
-#endif
-}
-
-void File::stat()
-{
-#if linux
-    if (!touchtime)
-    {
-	touchtime = mem.calloc(1, sizeof(struct stat));
-    }
-#endif
-#if _WIN32
-    HANDLE h;
-
-    if (!touchtime)
-    {
-	touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA));
-    }
-    h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime);
-    if (h != INVALID_HANDLE_VALUE)
-    {
-	FindClose(h);
-    }
-#endif
-}
-
-void File::checkoffset(size_t offset, size_t nbytes)
-{
-    if (offset > len || offset + nbytes > len)
-	error("Corrupt file '%s': offset x%"PRIxSIZE" off end of file",toChars(),offset);
-}
-
-char *File::toChars()
-{
-    return name->toChars();
-}
-
-
-/************************* OutBuffer *************************/
-
-OutBuffer::OutBuffer()
-{
-    data = NULL;
-    offset = 0;
-    size = 0;
-}
-
-OutBuffer::~OutBuffer()
-{
-    mem.free(data);
-}
-
-void *OutBuffer::extractData()
-{
-    void *p;
-
-    p = (void *)data;
-    data = NULL;
-    offset = 0;
-    size = 0;
-    return p;
-}
-
-void OutBuffer::mark()
-{
-    mem.mark(data);
-}
-
-void OutBuffer::reserve(unsigned nbytes)
-{
-    //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
-    if (size - offset < nbytes)
-    {
-	size = (offset + nbytes) * 2;
-	data = (unsigned char *)mem.realloc(data, size);
-    }
-}
-
-void OutBuffer::reset()
-{
-    offset = 0;
-}
-
-void OutBuffer::setsize(unsigned size)
-{
-    offset = size;
-}
-
-void OutBuffer::write(const void *data, unsigned nbytes)
-{
-    reserve(nbytes);
-    memcpy(this->data + offset, data, nbytes);
-    offset += nbytes;
-}
-
-void OutBuffer::writebstring(unsigned char *string)
-{
-    write(string,*string + 1);
-}
-
-void OutBuffer::writestring(char *string)
-{
-    write(string,strlen(string));
-}
-
-void OutBuffer::writedstring(const char *string)
-{
-#if M_UNICODE
-    for (; *string; string++)
-    {
-	writedchar(*string);
-    }
-#else
-    write(string,strlen(string));
-#endif
-}
-
-void OutBuffer::writedstring(const wchar_t *string)
-{
-#if M_UNICODE
-    write(string,wcslen(string) * sizeof(wchar_t));
-#else
-    for (; *string; string++)
-    {
-	writedchar(*string);
-    }
-#endif
-}
-
-void OutBuffer::prependstring(char *string)
-{   unsigned len;
-
-    len = strlen(string);
-    reserve(len);
-    memmove(data + len, data, offset);
-    memcpy(data, string, len);
-    offset += len;
-}
-
-void OutBuffer::writenl()
-{
-#if _WIN32
-#if M_UNICODE
-    write4(0x000A000D);		// newline is CR,LF on Microsoft OS's
-#else
-    writeword(0x0A0D);		// newline is CR,LF on Microsoft OS's
-#endif
-#else
-#if M_UNICODE
-    writeword('\n');
-#else
-    writeByte('\n');
-#endif
-#endif
-}
-
-void OutBuffer::writeByte(unsigned b)
-{
-    reserve(1);
-    this->data[offset] = (unsigned char)b;
-    offset++;
-}
-
-void OutBuffer::writeUTF8(unsigned b)
-{
-    reserve(6);
-    if (b <= 0x7F)
-    {
-	this->data[offset] = (unsigned char)b;
-	offset++;
-    }
-    else if (b <= 0x7FF)
-    {
-	this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
-	this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
-	offset += 2;
-    }
-    else if (b <= 0xFFFF)
-    {
-	this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
-	this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
-	this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
-	offset += 3;
-    }
-    else if (b <= 0x1FFFFF)
-    {
-	this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
-	this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
-	this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
-	this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
-	offset += 4;
-    }
-    else if (b <= 0x3FFFFFF)
-    {
-	this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
-	this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
-	this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
-	this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
-	this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
-	offset += 5;
-    }
-    else if (b <= 0x7FFFFFFF)
-    {
-	this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
-	this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
-	this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
-	this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
-	this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
-	this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
-	offset += 6;
-    }
-    else
-	assert(0);
-}
-
-void OutBuffer::writedchar(unsigned b)
-{
-    reserve(Dchar_mbmax * sizeof(dchar));
-    offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) -
-		this->data;
-}
-
-void OutBuffer::prependbyte(unsigned b)
-{
-    reserve(1);
-    memmove(data + 1, data, offset);
-    data[0] = (unsigned char)b;
-    offset++;
-}
-
-void OutBuffer::writeword(unsigned w)
-{
-    reserve(2);
-    *(unsigned short *)(this->data + offset) = (unsigned short)w;
-    offset += 2;
-}
-
-void OutBuffer::writeUTF16(unsigned w)
-{
-    reserve(4);
-    if (w <= 0xFFFF)
-    {
-	*(unsigned short *)(this->data + offset) = (unsigned short)w;
-	offset += 2;
-    }
-    else if (w <= 0x10FFFF)
-    {
-	*(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
-	*(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
-	offset += 4;
-    }
-    else
-	assert(0);
-}
-
-void OutBuffer::write4(unsigned w)
-{
-    reserve(4);
-    *(unsigned long *)(this->data + offset) = w;
-    offset += 4;
-}
-
-void OutBuffer::write(OutBuffer *buf)
-{
-    if (buf)
-    {	reserve(buf->offset);
-	memcpy(data + offset, buf->data, buf->offset);
-	offset += buf->offset;
-    }
-}
-
-void OutBuffer::write(Object *obj)
-{
-    if (obj)
-    {
-	writestring(obj->toChars());
-    }
-}
-
-void OutBuffer::fill0(unsigned nbytes)
-{
-    reserve(nbytes);
-    memset(data + offset,0,nbytes);
-    offset += nbytes;
-}
-
-void OutBuffer::align(unsigned size)
-{   unsigned nbytes;
-
-    nbytes = ((offset + size - 1) & ~(size - 1)) - offset;
-    fill0(nbytes);
-}
-
-void OutBuffer::vprintf(const char *format, va_list args)
-{
-    char buffer[128];
-    char *p;
-    unsigned psize;
-    int count;
-
-    p = buffer;
-    psize = sizeof(buffer);
-    for (;;)
-    {
-#if _WIN32
-	count = _vsnprintf(p,psize,format,args);
-	if (count != -1)
-	    break;
-	psize *= 2;
-#endif
-#if linux
-	count = vsnprintf(p,psize,format,args);
-	if (count == -1)
-	    psize *= 2;
-	else if (count >= psize)
-	    psize = count + 1;
-	else
-	    break;
-#endif
-	p = (char *) alloca(psize);	// buffer too small, try again with larger size
-    }
-    write(p,count);
-}
-
-#if M_UNICODE
-void OutBuffer::vprintf(const wchar_t *format, va_list args)
-{
-    dchar buffer[128];
-    dchar *p;
-    unsigned psize;
-    int count;
-
-    p = buffer;
-    psize = sizeof(buffer) / sizeof(buffer[0]);
-    for (;;)
-    {
-#if _WIN32
-	count = _vsnwprintf(p,psize,format,args);
-	if (count != -1)
-	    break;
-	psize *= 2;
-#endif
-#if linux
-	count = vsnwprintf(p,psize,format,args);
-	if (count == -1)
-	    psize *= 2;
-	else if (count >= psize)
-	    psize = count + 1;
-	else
-	    break;
-#endif
-	p = (dchar *) alloca(psize * 2);	// buffer too small, try again with larger size
-    }
-    write(p,count * 2);
-}
-#endif
-
-void OutBuffer::printf(const char *format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    vprintf(format,ap);
-    va_end(ap);
-}
-
-#if M_UNICODE
-void OutBuffer::printf(const wchar_t *format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    vprintf(format,ap);
-    va_end(ap);
-}
-#endif
-
-void OutBuffer::bracket(char left, char right)
-{
-    reserve(2);
-    memmove(data + 1, data, offset);
-    data[0] = left;
-    data[offset + 1] = right;
-    offset += 2;
-}
-
-/******************
- * Insert left at i, and right at j.
- * Return index just past right.
- */
-
-unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right)
-{
-    size_t leftlen = strlen(left);
-    size_t rightlen = strlen(right);
-    reserve(leftlen + rightlen);
-    insert(i, left, leftlen);
-    insert(j + leftlen, right, rightlen);
-    return j + leftlen + rightlen;
-}
-
-void OutBuffer::spread(unsigned offset, unsigned nbytes)
-{
-    reserve(nbytes);
-    memmove(data + offset + nbytes, data + offset,
-	this->offset - offset);
-    this->offset += nbytes;
-}
-
-/****************************************
- * Returns: offset + nbytes
- */
-
-unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
-{
-    spread(offset, nbytes);
-    memmove(data + offset, p, nbytes);
-    return offset + nbytes;
-}
-
-void OutBuffer::remove(unsigned offset, unsigned nbytes)
-{
-    memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
-    this->offset -= nbytes;
-}
-
-char *OutBuffer::toChars()
-{
-    writeByte(0);
-    return (char *)data;
-}
-
-/********************************* Bits ****************************/
-
-Bits::Bits()
-{
-    data = NULL;
-    bitdim = 0;
-    allocdim = 0;
-}
-
-Bits::~Bits()
-{
-    mem.free(data);
-}
-
-void Bits::mark()
-{
-    mem.mark(data);
-}
-
-void Bits::resize(unsigned bitdim)
-{
-    unsigned allocdim;
-    unsigned mask;
-
-    allocdim = (bitdim + 31) / 32;
-    data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
-    if (this->allocdim < allocdim)
-	memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
-
-    // Clear other bits in last word
-    mask = (1 << (bitdim & 31)) - 1;
-    if (mask)
-	data[allocdim - 1] &= ~mask;
-
-    this->bitdim = bitdim;
-    this->allocdim = allocdim;
-}
-
-void Bits::set(unsigned bitnum)
-{
-    data[bitnum / 32] |= 1 << (bitnum & 31);
-}
-
-void Bits::clear(unsigned bitnum)
-{
-    data[bitnum / 32] &= ~(1 << (bitnum & 31));
-}
-
-int Bits::test(unsigned bitnum)
-{
-    return data[bitnum / 32] & (1 << (bitnum & 31));
-}
-
-void Bits::set()
-{   unsigned mask;
-
-    memset(data, ~0, allocdim * sizeof(data[0]));
-
-    // Clear other bits in last word
-    mask = (1 << (bitdim & 31)) - 1;
-    if (mask)
-	data[allocdim - 1] &= mask;
-}
-
-void Bits::clear()
-{
-    memset(data, 0, allocdim * sizeof(data[0]));
-}
-
-void Bits::copy(Bits *from)
-{
-    assert(bitdim == from->bitdim);
-    memcpy(data, from->data, allocdim * sizeof(data[0]));
-}
-
-Bits *Bits::clone()
-{
-    Bits *b;
-
-    b = new Bits();
-    b->resize(bitdim);
-    b->copy(this);
-    return b;
-}
-
-void Bits::sub(Bits *b)
-{
-    unsigned u;
-
-    for (u = 0; u < allocdim; u++)
-	data[u] &= ~b->data[u];
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+
+#if linux
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "port.h"
+#include "root.h"
+#include "dchar.h"
+#include "mem.h"
+#include "mars.h"
+
+#if 0 //__SC__ //def DEBUG
+extern "C" void __cdecl _assert(void *e, void *f, unsigned line)
+{
+    printf("Assert('%s','%s',%d)\n",e,f,line);
+    fflush(stdout);
+    *(char *)0 = 0;
+}
+#endif
+
+/*************************************
+ * Convert wchar string to ascii string.
+ */
+
+char *wchar2ascii(wchar_t *us)
+{
+    return wchar2ascii(us, wcslen(us));
+}
+
+char *wchar2ascii(wchar_t *us, unsigned len)
+{
+    unsigned i;
+    char *p;
+
+    p = (char *)mem.malloc(len + 1);
+    for (i = 0; i <= len; i++)
+	p[i] = (char) us[i];
+    return p;
+}
+
+int wcharIsAscii(wchar_t *us)
+{
+    return wcharIsAscii(us, wcslen(us));
+}
+
+int wcharIsAscii(wchar_t *us, unsigned len)
+{
+    unsigned i;
+
+    for (i = 0; i <= len; i++)
+    {
+	if (us[i] & ~0xFF)	// if high bits set
+	    return 0;		// it's not ascii
+    }
+    return 1;
+}
+
+
+/***********************************
+ * Compare length-prefixed strings (bstr).
+ */
+
+int bstrcmp(unsigned char *b1, unsigned char *b2)
+{
+    return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1;
+}
+
+/***************************************
+ * Convert bstr into a malloc'd string.
+ */
+
+char *bstr2str(unsigned char *b)
+{
+    char *s;
+    unsigned len;
+
+    len = *b;
+    s = (char *) mem.malloc(len + 1);
+    s[len] = 0;
+    return (char *)memcpy(s,b + 1,len);
+}
+
+/**************************************
+ * Print error message and exit.
+ */
+
+void error(const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Error: ");
+    vprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+
+    exit(EXIT_FAILURE);
+}
+
+#if M_UNICODE
+void error(const dchar *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Error: ");
+    vwprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+
+    exit(EXIT_FAILURE);
+}
+#endif
+
+void error_mem()
+{
+    error("out of memory");
+}
+
+/**************************************
+ * Print warning message.
+ */
+
+void warning(const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Warning: ");
+    vprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+}
+
+/****************************** Object ********************************/
+
+int Object::equals(Object *o)
+{
+    return o == this;
+}
+
+hash_t Object::hashCode()
+{
+    return (hash_t) this;
+}
+
+int Object::compare(Object *obj)
+{
+    return this - obj;
+}
+
+void Object::print()
+{
+    printf("%s %p\n", toChars(), this);
+}
+
+char *Object::toChars()
+{
+    return "Object";
+}
+
+dchar *Object::toDchars()
+{
+#if M_UNICODE
+    return L"Object";
+#else
+    return toChars();
+#endif
+}
+
+int Object::dyncast()
+{
+    return 0;
+}
+
+void Object::toBuffer(OutBuffer *b)
+{
+    b->writestring("Object");
+}
+
+void Object::mark()
+{
+}
+
+/****************************** String ********************************/
+
+String::String(char *str, int ref)
+{
+    this->str = ref ? str : mem.strdup(str);
+    this->ref = ref;
+}
+
+String::~String()
+{
+    mem.free(str);
+}
+
+void String::mark()
+{
+    mem.mark(str);
+}
+
+hash_t String::calcHash(const char *str, size_t len)
+{
+    hash_t hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(uint16_t *)str;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += (*(uint16_t *)str << 8) +
+			((uint8_t *)str)[2];
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(uint32_t *)str;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+hash_t String::calcHash(const char *str)
+{
+    return calcHash(str, strlen(str));
+}
+
+hash_t String::hashCode()
+{
+    return calcHash(str, strlen(str));
+}
+
+unsigned String::len()
+{
+    return strlen(str);
+}
+
+int String::equals(Object *obj)
+{
+    return strcmp(str,((String *)obj)->str) == 0;
+}
+
+int String::compare(Object *obj)
+{
+    return strcmp(str,((String *)obj)->str);
+}
+
+char *String::toChars()
+{
+    return str;
+}
+
+void String::print()
+{
+    printf("String '%s'\n",str);
+}
+
+
+/****************************** FileName ********************************/
+
+FileName::FileName(char *str, int ref)
+    : String(str,ref)
+{
+}
+
+char *FileName::combine(char *path, char *name)
+{   char *f;
+    size_t pathlen;
+    size_t namelen;
+
+    if (!path || !*path)
+	return name;
+    pathlen = strlen(path);
+    namelen = strlen(name);
+    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if linux
+    if (path[pathlen - 1] != '/')
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+#endif
+#if _WIN32
+    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
+    {	f[pathlen] = '\\';
+	pathlen++;
+    }
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+FileName::FileName(char *path, char *name)
+    : String(combine(path,name),1)
+{
+}
+
+// Split a path into an Array of paths
+Array *FileName::splitPath(const char *path)
+{
+    char c = 0;				// unnecessary initializer is for VC /W4
+    const char *p;
+    OutBuffer buf;
+    Array *array;
+
+    array = new Array();
+    if (path)
+    {
+	p = path;
+	do
+	{   char instring = 0;
+
+	    while (isspace(*p))		// skip leading whitespace
+		p++;
+	    buf.reserve(strlen(p) + 1);	// guess size of path
+	    for (; ; p++)
+	    {
+		c = *p;
+		switch (c)
+		{
+		    case '"':
+			instring ^= 1;	// toggle inside/outside of string
+			continue;
+
+#if MACINTOSH
+		    case ',':
+#endif
+#if _WIN32
+		    case ';':
+#endif
+#if linux
+		    case ':':
+#endif
+			p++;
+			break;		// note that ; cannot appear as part
+					// of a path, quotes won't protect it
+
+		    case 0x1A:		// ^Z means end of file
+		    case 0:
+			break;
+
+		    case '\r':
+			continue;	// ignore carriage returns
+
+#if linux
+		    case '~':
+			buf.writestring(getenv("HOME"));
+			continue;
+#endif
+
+		    case ' ':
+		    case '\t':		// tabs in filenames?
+			if (!instring)	// if not in string
+			    break;	// treat as end of path
+		    default:
+			buf.writeByte(c);
+			continue;
+		}
+		break;
+	    }
+	    if (buf.offset)		// if path is not empty
+	    {
+		buf.writeByte(0);	// to asciiz
+		array->push(buf.extractData());
+	    }
+	} while (c);
+    }
+    return array;
+}
+
+hash_t FileName::hashCode()
+{
+#if _WIN32
+    // We need a different hashCode because it must be case-insensitive
+    size_t len = strlen(str);
+    hash_t hash = 0;
+    unsigned char *s = (unsigned char *)str;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(uint8_t *)s | 0x20;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(uint16_t *)s | 0x2020;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += ((*(uint16_t *)s << 8) +
+			 ((uint8_t *)s)[2]) | 0x202020;
+		break;
+
+	    default:
+		hash *= 37;
+		hash += *(uint32_t *)s | 0x20202020;
+		s += 4;
+		len -= 4;
+		break;
+	}
+    }
+#else
+    // darwin HFS is case insensitive, though...
+    return String::hashCode();
+#endif
+}
+
+int FileName::compare(Object *obj)
+{
+#if _WIN32
+    return stricmp(str,((FileName *)obj)->str);
+#else
+    return String::compare(obj);
+#endif
+}
+
+int FileName::equals(Object *obj)
+{
+#if _WIN32
+    return stricmp(str,((FileName *)obj)->str) == 0;
+#else
+    return String::equals(obj);
+#endif
+}
+
+/************************************
+ * Return !=0 if absolute path name.
+ */
+
+int FileName::absolute(const char *name)
+{
+#if _WIN32
+    return (*name == '\\') ||
+	   (*name == '/')  ||
+	   (*name && name[1] == ':');
+#endif
+#if linux
+    return (*name == '/');
+#endif
+}
+
+/********************************
+ * Return filename extension (read-only).
+ * Points past '.' of extension.
+ * If there isn't one, return NULL.
+ */
+
+char *FileName::ext(const char *str)
+{
+    char *e;
+    size_t len = strlen(str);
+
+    e = (char *)str + len;
+    for (;;)
+    {
+	switch (*e)
+	{   case '.':
+		return e + 1;
+#if linux
+	    case '/':
+	        break;
+#endif
+#if _WIN32
+	    case '\\':
+	    case ':':
+	    case '/':
+		break;
+#endif
+	    default:
+		if (e == str)
+		    break;
+		e--;
+		continue;
+	}
+	return NULL;
+    }
+}
+
+char *FileName::ext()
+{
+    return ext(str);
+}
+
+/********************************
+ * Return mem.malloc'd filename with extension removed.
+ */
+
+char *FileName::removeExt(const char *str)
+{
+    const char *e = ext(str);
+    if (e)
+    {	size_t len = (e - str) - 1;
+	char *n = (char *)mem.malloc(len + 1);
+	memcpy(n, str, len);
+	n[len] = 0;
+	return n;
+    }
+    return mem.strdup(str);
+}
+
+/********************************
+ * Return filename name excluding path (read-only).
+ */
+
+char *FileName::name(const char *str)
+{
+    char *e;
+    size_t len = strlen(str);
+
+    e = (char *)str + len;
+    for (;;)
+    {
+	switch (*e)
+	{
+#if linux
+	    case '/':
+	       return e + 1;
+#endif
+#if _WIN32
+	    case '\\':
+	    case ':':
+		return e + 1;
+#endif
+	    default:
+		if (e == str)
+		    break;
+		e--;
+		continue;
+	}
+	return e;
+    }
+}
+
+char *FileName::name()
+{
+    return name(str);
+}
+
+/**************************************
+ * Return path portion of str.
+ * Path will does not include trailing path separator.
+ */
+
+char *FileName::path(const char *str)
+{
+    char *n = name(str);
+    char *path;
+    size_t pathlen;
+
+    if (n > str)
+    {
+#if linux
+	if (n[-1] == '/')
+	    n--;
+#endif
+#if _WIN32
+	if (n[-1] == '\\')
+	    n--;
+#endif
+    }
+    pathlen = n - str;
+    path = (char *)mem.malloc(pathlen + 1);
+    memcpy(path, str, pathlen);
+    path[pathlen] = 0;
+    return path;
+}
+
+/**************************************
+ * Replace filename portion of path.
+ */
+
+char *FileName::replaceName(char *path, char *name)
+{   char *f;
+    char *n;
+    size_t pathlen;
+    size_t namelen;
+
+    if (absolute(name))
+	return name;
+
+    n = FileName::name(path);
+    if (n == path)
+	return name;
+    pathlen = n - path;
+    namelen = strlen(name);
+    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if linux
+    if (path[pathlen - 1] != '/')
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+#endif
+#if _WIN32
+    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
+    {	f[pathlen] = '\\';
+	pathlen++;
+    }
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+/***************************
+ */
+
+FileName *FileName::defaultExt(const char *name, const char *ext)
+{
+    char *e;
+    char *s;
+    size_t len;
+    size_t extlen;
+
+    e = FileName::ext(name);
+    if (e)				// if already has an extension
+	return new FileName((char *)name, 0);
+
+    len = strlen(name);
+    extlen = strlen(ext);
+    s = (char *)alloca(len + 1 + extlen + 1);
+    memcpy(s,name,len);
+    s[len] = '.';
+    memcpy(s + len + 1, ext, extlen + 1);
+    return new FileName(s, 0);
+}
+
+/***************************
+ */
+
+FileName *FileName::forceExt(const char *name, const char *ext)
+{
+    char *e;
+    char *s;
+    size_t len;
+    size_t extlen;
+
+    e = FileName::ext(name);
+    if (e)				// if already has an extension
+    {
+	len = e - name;
+	extlen = strlen(ext);
+
+	s = (char *)alloca(len + extlen + 1);
+	memcpy(s,name,len);
+	memcpy(s + len, ext, extlen + 1);
+	return new FileName(s, 0);
+    }
+    else
+	return defaultExt(name, ext);	// doesn't have one
+}
+
+/******************************
+ * Return !=0 if extensions match.
+ */
+
+int FileName::equalsExt(const char *ext)
+{   const char *e;
+
+    e = FileName::ext();
+    if (!e && !ext)
+	return 1;
+    if (!e || !ext)
+	return 0;
+#if linux
+    return strcmp(e,ext) == 0;
+#endif
+#if _WIN32
+    return stricmp(e,ext) == 0;
+#endif
+}
+
+/*************************************
+ * Copy file from this to to.
+ */
+
+void FileName::CopyTo(FileName *to)
+{
+    File file(this);
+
+#if _WIN32
+    file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));	// keep same file time
+#endif
+#if linux
+    file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time
+#endif
+    file.readv();
+    file.name = to;
+    file.writev();
+}
+
+/*************************************
+ * Search Path for file.
+ * Input:
+ *	cwd	if !=0, search current directory before searching path
+ */
+
+char *FileName::searchPath(Array *path, char *name, int cwd)
+{
+    if (absolute(name))
+    {
+	return exists(name) ? name : NULL;
+    }
+    if (cwd)
+    {
+	if (exists(name))
+	    return name;
+    }
+    if (path)
+    {	unsigned i;
+
+	for (i = 0; i < path->dim; i++)
+	{
+	    char *p = (char *)path->data[i];
+	    char *n = combine(p, name);
+
+	    if (exists(n))
+		return n;
+	}
+    }
+    return NULL;
+}
+
+int FileName::exists(const char *name)
+{
+#if linux
+    struct stat st;
+
+    if (stat(name, &st) < 0)
+	return 0;
+    if (S_ISDIR(st.st_mode))
+	return 2;
+    return 1;
+#endif
+#if _WIN32
+    DWORD dw;
+    int result;
+
+    dw = GetFileAttributesA(name);
+    if (dw == -1L)
+	result = 0;
+    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+	result = 2;
+    else
+	result = 1;
+    return result;
+#endif
+}
+
+void FileName::ensurePathExists(const char *path)
+{
+    //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
+    if (path && *path)
+    {
+	if (!exists(path))
+	{
+	    char *p = FileName::path(path);
+	    if (*p)
+	    {
+#if _WIN32
+		size_t len = strlen(p);
+		if (len > 2 && p[-1] == ':')
+		{   mem.free(p);
+		    return;
+		}
+#endif
+		ensurePathExists(p);
+		mem.free(p);
+	    }
+#if _WIN32
+	    if (path[strlen(path) - 1] != '\\')
+#endif
+#if linux
+	    if (path[strlen(path) - 1] != '\\')
+#endif
+	    {
+		//printf("mkdir(%s)\n", path);
+#if _WIN32
+		if (mkdir(path))
+#endif
+#if linux
+		if (mkdir(path, 0777))
+#endif
+		    error("cannot create directory %s", path);
+	    }
+	}
+    }
+}
+
+/****************************** File ********************************/
+
+File::File(FileName *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    touchtime = NULL;
+    name = n;
+}
+
+File::File(char *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    touchtime = NULL;
+    name = new FileName(n, 0);
+}
+
+File::~File()
+{
+    if (buffer)
+    {
+	if (ref == 0)
+	    mem.free(buffer);
+#if _WIN32
+	else if (ref == 2)
+	    UnmapViewOfFile(buffer);
+#endif
+    }
+    if (touchtime)
+	mem.free(touchtime);
+}
+
+void File::mark()
+{
+    mem.mark(buffer);
+    mem.mark(touchtime);
+    mem.mark(name);
+}
+
+/*************************************
+ */
+
+int File::read()
+{
+#if linux
+    off_t size;
+    ssize_t numread;
+    int fd;
+    struct stat buf;
+    int result = 0;
+    char *name;
+
+    name = this->name->toChars();
+    //printf("File::read('%s')\n",name);
+    fd = open(name, O_RDONLY);
+    if (fd == -1)
+    {	result = errno;
+	//printf("\topen error, errno = %d\n",errno);
+	goto err1;
+    }
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 0;       // we own the buffer now
+
+    //printf("\tfile opened\n");
+    if (fstat(fd, &buf))
+    {
+	printf("\tfstat error, errno = %d\n",errno);
+        goto err2;
+    }
+    size = buf.st_size;
+    buffer = (unsigned char *) mem.malloc(size + 2);
+    if (!buffer)
+    {
+	printf("\tmalloc error, errno = %d\n",errno);
+	goto err2;
+    }
+
+    numread = ::read(fd, buffer, size);
+    if (numread != size)
+    {
+	printf("\tread error, errno = %d\n",errno);
+	goto err2;
+    }
+
+    if (touchtime)
+        memcpy(touchtime, &buf, sizeof(buf));
+
+    if (close(fd) == -1)
+    {
+	printf("\tclose error, errno = %d\n",errno);
+	goto err;
+    }
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;		// ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return 0;
+
+err2:
+    close(fd);
+err:
+    mem.free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    result = 1;
+    return result;
+#endif
+#if _WIN32
+    DWORD size;
+    DWORD numread;
+    HANDLE h;
+    int result = 0;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err1;
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 0;
+
+    size = GetFileSize(h,NULL);
+    buffer = (unsigned char *) mem.malloc(size + 2);
+    if (!buffer)
+	goto err2;
+
+    if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
+	goto err2;
+
+    if (numread != size)
+	goto err2;
+
+    if (touchtime)
+    {
+	if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime))
+	    goto err2;
+    }
+
+    if (!CloseHandle(h))
+	goto err;
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;		// ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return 0;
+
+err2:
+    CloseHandle(h);
+err:
+    mem.free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    result = 1;
+    return result;
+#endif
+}
+
+/*****************************
+ * Read a file with memory mapped file I/O.
+ */
+
+int File::mmread()
+{
+#if linux
+    return read();
+#endif
+#if _WIN32
+    HANDLE hFile;
+    HANDLE hFileMap;
+    DWORD size;
+    char *name;
+
+    name = this->name->toChars();
+    hFile = CreateFile(name, GENERIC_READ,
+			FILE_SHARE_READ, NULL,
+			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+	goto Lerr;
+    size = GetFileSize(hFile, NULL);
+    //printf(" file created, size %d\n", size);
+
+    hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL);
+    if (CloseHandle(hFile) != TRUE)
+	goto Lerr;
+
+    if (hFileMap == NULL)
+	goto Lerr;
+
+    //printf(" mapping created\n");
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 2;
+    buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL);
+    if (CloseHandle(hFileMap) != TRUE)
+	goto Lerr;
+    if (buffer == NULL)			// mapping view failed
+	goto Lerr;
+
+    len = size;
+    //printf(" buffer = %p\n", buffer);
+
+    return 0;
+
+Lerr:
+    return GetLastError();			// failure
+#endif
+}
+
+/*********************************************
+ * Write a file.
+ * Returns:
+ *	0	success
+ */
+
+int File::write()
+{
+#if linux
+    int fd;
+    ssize_t numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+    if (fd == -1)
+	goto err;
+
+    numwritten = ::write(fd, buffer, len);
+    if (len != numwritten)
+	goto err2;
+    
+    if (close(fd) == -1)
+	goto err;
+
+    if (touchtime)
+    {   struct utimbuf ubuf;
+
+        ubuf.actime = ((struct stat *)touchtime)->st_atime;
+        ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
+	if (utime(name, &ubuf))
+	    goto err;
+    }
+    return 0;
+
+err2:
+    close(fd);
+    ::remove(name);
+err:
+    return 1;
+#endif
+#if _WIN32
+    HANDLE h;
+    DWORD numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+	goto err2;
+
+    if (len != numwritten)
+	goto err2;
+    
+    if (touchtime) {
+        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
+    }
+    if (!CloseHandle(h))
+	goto err;
+    return 0;
+
+err2:
+    CloseHandle(h);
+    DeleteFileA(name);
+err:
+    return 1;
+#endif
+}
+
+/*********************************************
+ * Append to a file.
+ * Returns:
+ *	0	success
+ */
+
+int File::append()
+{
+#if linux
+    return 1;
+#endif
+#if _WIN32
+    HANDLE h;
+    DWORD numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+#if 1
+    SetFilePointer(h, 0, NULL, FILE_END);
+#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition
+    if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+	goto err;
+#endif
+
+    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+	goto err2;
+
+    if (len != numwritten)
+	goto err2;
+    
+    if (touchtime) {
+        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
+    }
+    if (!CloseHandle(h))
+	goto err;
+    return 0;
+
+err2:
+    CloseHandle(h);
+err:
+    return 1;
+#endif
+}
+
+/**************************************
+ */
+
+void File::readv()
+{
+    if (read())
+	error("Error reading file '%s'\n",name->toChars());
+}
+
+/**************************************
+ */
+
+void File::mmreadv()
+{
+    if (mmread())
+	readv();
+}
+
+void File::writev()
+{
+    if (write())
+	error("Error writing file '%s'\n",name->toChars());
+}
+
+void File::appendv()
+{
+    if (write())
+	error("Error appending to file '%s'\n",name->toChars());
+}
+
+/*******************************************
+ * Return !=0 if file exists.
+ *	0:	file doesn't exist
+ *	1:	normal file
+ *	2:	directory
+ */
+
+int File::exists()
+{
+#if linux
+    return 0;
+#endif
+#if _WIN32
+    DWORD dw;
+    int result;
+    char *name;
+
+    name = this->name->toChars();
+    if (touchtime)
+	dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes;
+    else
+	dw = GetFileAttributesA(name);
+    if (dw == -1L)
+	result = 0;
+    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+	result = 2;
+    else
+	result = 1;
+    return result;
+#endif
+}
+
+void File::remove()
+{
+#if linux
+    ::remove(this->name->toChars());
+#endif
+#if _WIN32
+    DeleteFileA(this->name->toChars());
+#endif
+}
+
+Array *File::match(char *n)
+{
+    return match(new FileName(n, 0));
+}
+
+Array *File::match(FileName *n)
+{
+#if linux
+    return NULL;
+#endif
+#if _WIN32
+    HANDLE h;
+    WIN32_FIND_DATAA fileinfo;
+    Array *a;
+    char *c;
+    char *name;
+
+    a = new Array();
+    c = n->toChars();
+    name = n->name();
+    h = FindFirstFileA(c,&fileinfo);
+    if (h != INVALID_HANDLE_VALUE)
+    {
+	do
+	{
+	    // Glue path together with name
+	    char *fn;
+	    File *f;
+
+	    fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
+	    memcpy(fn, c, name - c);
+	    strcpy(fn + (name - c), fileinfo.cFileName);
+	    f = new File(fn);
+	    f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
+	    memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
+	    a->push(f);
+	} while (FindNextFileA(h,&fileinfo) != FALSE);
+	FindClose(h);
+    }
+    return a;
+#endif
+}
+
+int File::compareTime(File *f)
+{
+#if linux
+    return 0;
+#endif
+#if _WIN32
+    if (!touchtime)
+	stat();
+    if (!f->touchtime)
+	f->stat();
+    return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime);
+#endif
+}
+
+void File::stat()
+{
+#if linux
+    if (!touchtime)
+    {
+	touchtime = mem.calloc(1, sizeof(struct stat));
+    }
+#endif
+#if _WIN32
+    HANDLE h;
+
+    if (!touchtime)
+    {
+	touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA));
+    }
+    h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime);
+    if (h != INVALID_HANDLE_VALUE)
+    {
+	FindClose(h);
+    }
+#endif
+}
+
+void File::checkoffset(size_t offset, size_t nbytes)
+{
+    if (offset > len || offset + nbytes > len)
+	error("Corrupt file '%s': offset x%"PRIxSIZE" off end of file",toChars(),offset);
+}
+
+char *File::toChars()
+{
+    return name->toChars();
+}
+
+
+/************************* OutBuffer *************************/
+
+OutBuffer::OutBuffer()
+{
+    data = NULL;
+    offset = 0;
+    size = 0;
+}
+
+OutBuffer::~OutBuffer()
+{
+    mem.free(data);
+}
+
+void *OutBuffer::extractData()
+{
+    void *p;
+
+    p = (void *)data;
+    data = NULL;
+    offset = 0;
+    size = 0;
+    return p;
+}
+
+void OutBuffer::mark()
+{
+    mem.mark(data);
+}
+
+void OutBuffer::reserve(unsigned nbytes)
+{
+    //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (size - offset < nbytes)
+    {
+	size = (offset + nbytes) * 2;
+	data = (unsigned char *)mem.realloc(data, size);
+    }
+}
+
+void OutBuffer::reset()
+{
+    offset = 0;
+}
+
+void OutBuffer::setsize(unsigned size)
+{
+    offset = size;
+}
+
+void OutBuffer::write(const void *data, unsigned nbytes)
+{
+    reserve(nbytes);
+    memcpy(this->data + offset, data, nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::writebstring(unsigned char *string)
+{
+    write(string,*string + 1);
+}
+
+void OutBuffer::writestring(const char *string)
+{
+    write(string,strlen(string));
+}
+
+void OutBuffer::writedstring(const char *string)
+{
+#if M_UNICODE
+    for (; *string; string++)
+    {
+	writedchar(*string);
+    }
+#else
+    write(string,strlen(string));
+#endif
+}
+
+void OutBuffer::writedstring(const wchar_t *string)
+{
+#if M_UNICODE
+    write(string,wcslen(string) * sizeof(wchar_t));
+#else
+    for (; *string; string++)
+    {
+	writedchar(*string);
+    }
+#endif
+}
+
+void OutBuffer::prependstring(char *string)
+{   unsigned len;
+
+    len = strlen(string);
+    reserve(len);
+    memmove(data + len, data, offset);
+    memcpy(data, string, len);
+    offset += len;
+}
+
+void OutBuffer::writenl()
+{
+#if _WIN32
+#if M_UNICODE
+    write4(0x000A000D);		// newline is CR,LF on Microsoft OS's
+#else
+    writeword(0x0A0D);		// newline is CR,LF on Microsoft OS's
+#endif
+#else
+#if M_UNICODE
+    writeword('\n');
+#else
+    writeByte('\n');
+#endif
+#endif
+}
+
+void OutBuffer::writeByte(unsigned b)
+{
+    reserve(1);
+    this->data[offset] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writeUTF8(unsigned b)
+{
+    reserve(6);
+    if (b <= 0x7F)
+    {
+	this->data[offset] = (unsigned char)b;
+	offset++;
+    }
+    else if (b <= 0x7FF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
+	this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 2;
+    }
+    else if (b <= 0xFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
+	this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 3;
+    }
+    else if (b <= 0x1FFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
+	this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 4;
+    }
+    else if (b <= 0x3FFFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
+	this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 5;
+    }
+    else if (b <= 0x7FFFFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
+	this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 6;
+    }
+    else
+	assert(0);
+}
+
+void OutBuffer::writedchar(unsigned b)
+{
+    reserve(Dchar_mbmax * sizeof(dchar));
+    offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) -
+		this->data;
+}
+
+void OutBuffer::prependbyte(unsigned b)
+{
+    reserve(1);
+    memmove(data + 1, data, offset);
+    data[0] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writeword(unsigned w)
+{
+    reserve(2);
+    *(unsigned short *)(this->data + offset) = (unsigned short)w;
+    offset += 2;
+}
+
+void OutBuffer::writeUTF16(unsigned w)
+{
+    reserve(4);
+    if (w <= 0xFFFF)
+    {
+	*(unsigned short *)(this->data + offset) = (unsigned short)w;
+	offset += 2;
+    }
+    else if (w <= 0x10FFFF)
+    {
+	*(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
+	*(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
+	offset += 4;
+    }
+    else
+	assert(0);
+}
+
+void OutBuffer::write4(unsigned w)
+{
+    reserve(4);
+    *(unsigned long *)(this->data + offset) = w;
+    offset += 4;
+}
+
+void OutBuffer::write(OutBuffer *buf)
+{
+    if (buf)
+    {	reserve(buf->offset);
+	memcpy(data + offset, buf->data, buf->offset);
+	offset += buf->offset;
+    }
+}
+
+void OutBuffer::write(Object *obj)
+{
+    if (obj)
+    {
+	writestring(obj->toChars());
+    }
+}
+
+void OutBuffer::fill0(unsigned nbytes)
+{
+    reserve(nbytes);
+    memset(data + offset,0,nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::align(unsigned size)
+{   unsigned nbytes;
+
+    nbytes = ((offset + size - 1) & ~(size - 1)) - offset;
+    fill0(nbytes);
+}
+
+void OutBuffer::vprintf(const char *format, va_list args)
+{
+    char buffer[128];
+    char *p;
+    unsigned psize;
+    int count;
+
+    p = buffer;
+    psize = sizeof(buffer);
+    for (;;)
+    {
+#if _WIN32
+	count = _vsnprintf(p,psize,format,args);
+	if (count != -1)
+	    break;
+	psize *= 2;
+#endif
+#if linux
+	count = vsnprintf(p,psize,format,args);
+	if (count == -1)
+	    psize *= 2;
+	else if (count >= psize)
+	    psize = count + 1;
+	else
+	    break;
+#endif
+	p = (char *) alloca(psize);	// buffer too small, try again with larger size
+    }
+    write(p,count);
+}
+
+#if M_UNICODE
+void OutBuffer::vprintf(const wchar_t *format, va_list args)
+{
+    dchar buffer[128];
+    dchar *p;
+    unsigned psize;
+    int count;
+
+    p = buffer;
+    psize = sizeof(buffer) / sizeof(buffer[0]);
+    for (;;)
+    {
+#if _WIN32
+	count = _vsnwprintf(p,psize,format,args);
+	if (count != -1)
+	    break;
+	psize *= 2;
+#endif
+#if linux
+	count = vsnwprintf(p,psize,format,args);
+	if (count == -1)
+	    psize *= 2;
+	else if (count >= psize)
+	    psize = count + 1;
+	else
+	    break;
+#endif
+	p = (dchar *) alloca(psize * 2);	// buffer too small, try again with larger size
+    }
+    write(p,count * 2);
+}
+#endif
+
+void OutBuffer::printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format,ap);
+    va_end(ap);
+}
+
+#if M_UNICODE
+void OutBuffer::printf(const wchar_t *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format,ap);
+    va_end(ap);
+}
+#endif
+
+void OutBuffer::bracket(char left, char right)
+{
+    reserve(2);
+    memmove(data + 1, data, offset);
+    data[0] = left;
+    data[offset + 1] = right;
+    offset += 2;
+}
+
+/******************
+ * Insert left at i, and right at j.
+ * Return index just past right.
+ */
+
+unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right)
+{
+    size_t leftlen = strlen(left);
+    size_t rightlen = strlen(right);
+    reserve(leftlen + rightlen);
+    insert(i, left, leftlen);
+    insert(j + leftlen, right, rightlen);
+    return j + leftlen + rightlen;
+}
+
+void OutBuffer::spread(unsigned offset, unsigned nbytes)
+{
+    reserve(nbytes);
+    memmove(data + offset + nbytes, data + offset,
+	this->offset - offset);
+    this->offset += nbytes;
+}
+
+/****************************************
+ * Returns: offset + nbytes
+ */
+
+unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
+{
+    spread(offset, nbytes);
+    memmove(data + offset, p, nbytes);
+    return offset + nbytes;
+}
+
+void OutBuffer::remove(unsigned offset, unsigned nbytes)
+{
+    memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
+    this->offset -= nbytes;
+}
+
+char *OutBuffer::toChars()
+{
+    writeByte(0);
+    return (char *)data;
+}
+
+/********************************* Bits ****************************/
+
+Bits::Bits()
+{
+    data = NULL;
+    bitdim = 0;
+    allocdim = 0;
+}
+
+Bits::~Bits()
+{
+    mem.free(data);
+}
+
+void Bits::mark()
+{
+    mem.mark(data);
+}
+
+void Bits::resize(unsigned bitdim)
+{
+    unsigned allocdim;
+    unsigned mask;
+
+    allocdim = (bitdim + 31) / 32;
+    data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
+    if (this->allocdim < allocdim)
+	memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
+
+    // Clear other bits in last word
+    mask = (1 << (bitdim & 31)) - 1;
+    if (mask)
+	data[allocdim - 1] &= ~mask;
+
+    this->bitdim = bitdim;
+    this->allocdim = allocdim;
+}
+
+void Bits::set(unsigned bitnum)
+{
+    data[bitnum / 32] |= 1 << (bitnum & 31);
+}
+
+void Bits::clear(unsigned bitnum)
+{
+    data[bitnum / 32] &= ~(1 << (bitnum & 31));
+}
+
+int Bits::test(unsigned bitnum)
+{
+    return data[bitnum / 32] & (1 << (bitnum & 31));
+}
+
+void Bits::set()
+{   unsigned mask;
+
+    memset(data, ~0, allocdim * sizeof(data[0]));
+
+    // Clear other bits in last word
+    mask = (1 << (bitdim & 31)) - 1;
+    if (mask)
+	data[allocdim - 1] &= mask;
+}
+
+void Bits::clear()
+{
+    memset(data, 0, allocdim * sizeof(data[0]));
+}
+
+void Bits::copy(Bits *from)
+{
+    assert(bitdim == from->bitdim);
+    memcpy(data, from->data, allocdim * sizeof(data[0]));
+}
+
+Bits *Bits::clone()
+{
+    Bits *b;
+
+    b = new Bits();
+    b->resize(bitdim);
+    b->copy(this);
+    return b;
+}
+
+void Bits::sub(Bits *b)
+{
+    unsigned u;
+
+    for (u = 0; u < allocdim; u++)
+	data[u] &= ~b->data[u];
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- a/dmd/root.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/root.h	Sat Jul 12 19:38:31 2008 +0200
@@ -125,6 +125,7 @@
     static int absolute(const char *name);
     static char *ext(const char *);
     char *ext();
+    static char *removeExt(const char *str);
     static char *name(const char *);
     char *name();
     static char *path(const char *);
@@ -263,7 +264,7 @@
     void reset();
     void write(const void *data, unsigned nbytes);
     void writebstring(unsigned char *string);
-    void writestring(char *string);
+    void writestring(const char *string);
     void writedstring(const char *string);
     void writedstring(const wchar_t *string);
     void prependstring(char *string);
--- a/dmd/statement.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/statement.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -113,6 +113,16 @@
     return FALSE;
 }
 
+/* Only valid after semantic analysis
+ */
+int Statement::blockExit()
+{
+    printf("Statement::blockExit(%p)\n", this);
+    printf("%s\n", toChars());
+    assert(0);
+    return BEany;
+}
+
 // TRUE if statement may fall off the end without a throw or return
 
 int Statement::fallOffEnd()
@@ -197,6 +207,25 @@
     return this;
 }
 
+int ExpStatement::blockExit()
+{   int result = BEfallthru;
+
+    if (exp)
+    {
+	if (exp->op == TOKhalt)
+	    return BEhalt;
+	if (exp->op == TOKassert)
+	{   AssertExp *a = (AssertExp *)exp;
+
+	    if (a->e1->isBool(FALSE))	// if it's an assert(0)
+		return BEhalt;
+	}
+	if (exp->canThrow())
+	    result |= BEthrow;
+    }
+    return result;
+}
+
 int ExpStatement::fallOffEnd()
 {
     if (exp)
@@ -237,15 +266,15 @@
         buf->writenl();
 }
 
-Statement *CompileStatement::semantic(Scope *sc)
+Statements *CompileStatement::flatten(Scope *sc)
 {
-    //printf("CompileStatement::semantic() %s\n", exp->toChars());
+    //printf("CompileStatement::flatten() %s\n", exp->toChars());
     exp = exp->semantic(sc);
     exp = resolveProperties(sc, exp);
     exp = exp->optimize(WANTvalue | WANTinterpret);
     if (exp->op != TOKstring)
     {	error("argument to mixin must be a string, not (%s)", exp->toChars());
-	return this;
+	return NULL;
     }
     StringExp *se = (StringExp *)exp;
     se = se->toUTF8(sc);
@@ -253,14 +282,22 @@
     p.loc = loc;
     p.nextToken();
 
-    Statements *statements = new Statements();
+    Statements *a = new Statements();
     while (p.token.value != TOKeof)
     {
 	Statement *s = p.parseStatement(PSsemi | PScurlyscope);
-	statements->push(s);
+	a->push(s);
     }
-
-    Statement *s = new CompoundStatement(loc, statements);
+    return a;
+}
+
+Statement *CompileStatement::semantic(Scope *sc)
+{
+    //printf("CompileStatement::semantic() %s\n", exp->toChars());
+    Statements *a = flatten(sc);
+    if (!a)
+	return NULL;
+    Statement *s = new CompoundStatement(loc, a);
     return s->semantic(sc);
 }
 
@@ -468,7 +505,9 @@
 	i++;
     }
     if (statements->dim == 1 && !isAsmBlockStatement())
-	return s;
+    {
+	return (Statement *)statements->data[0];
+    }
     return this;
 }
 
@@ -478,13 +517,11 @@
 }
 
 ReturnStatement *CompoundStatement::isReturnStatement()
-{   int i;
+{
     ReturnStatement *rs = NULL;
 
-    for (i = 0; i < statements->dim; i++)
-    {	Statement *s;
-
-	s = (Statement *) statements->data[i];
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
 	if (s)
 	{
 	    rs = s->isReturnStatement();
@@ -496,12 +533,9 @@
 }
 
 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{   int i;
-
-    for (i = 0; i < statements->dim; i++)
-    {	Statement *s;
-
-	s = (Statement *) statements->data[i];
+{
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
 	if (s)
 	    s->toCBuffer(buf, hgs);
     }
@@ -510,15 +544,38 @@
 int CompoundStatement::usesEH()
 {
     for (int i = 0; i < statements->dim; i++)
-    {	Statement *s;
-
-	s = (Statement *) statements->data[i];
+    {	Statement *s = (Statement *) statements->data[i];
 	if (s && s->usesEH())
 	    return TRUE;
     }
     return FALSE;
 }
 
+int CompoundStatement::blockExit()
+{
+    //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
+    int result = BEfallthru;
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+//printf("result = x%x\n", result);
+//printf("%s\n", s->toChars());
+	    if (!(result & BEfallthru) && !s->comeFrom())
+	    {
+		if (global.params.warnings)
+		{   fprintf(stdmsg, "warning - ");
+		    s->error("statement is not reachable");
+		}
+	    }
+
+	    result &= ~BEfallthru;
+	    result |= s->blockExit();
+	}
+    }
+    return result;
+}
+
 int CompoundStatement::fallOffEnd()
 {   int falloff = TRUE;
 
@@ -634,15 +691,27 @@
 int UnrolledLoopStatement::usesEH()
 {
     for (size_t i = 0; i < statements->dim; i++)
-    {	Statement *s;
-
-	s = (Statement *) statements->data[i];
+    {	Statement *s = (Statement *) statements->data[i];
 	if (s && s->usesEH())
 	    return TRUE;
     }
     return FALSE;
 }
 
+int UnrolledLoopStatement::blockExit()
+{
+    int result = BEfallthru;
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    int r = s->blockExit();
+	    result |= r & ~(BEbreak | BEcontinue);
+	}
+    }
+    return result;
+}
+
 int UnrolledLoopStatement::fallOffEnd()
 {
     //printf("UnrolledLoopStatement::fallOffEnd()\n");
@@ -655,7 +724,6 @@
     return TRUE;
 }
 
-
 int UnrolledLoopStatement::comeFrom()
 {   int comefrom = FALSE;
 
@@ -743,6 +811,12 @@
     return statement ? statement->usesEH() : FALSE;
 }
 
+int ScopeStatement::blockExit()
+{
+    //printf("ScopeStatement::blockExit(%p)\n", statement);
+    return statement ? statement->blockExit() : BEfallthru;
+}
+
 int ScopeStatement::fallOffEnd()
 {
     return statement ? statement->fallOffEnd() : TRUE;
@@ -844,6 +918,35 @@
     return body ? body->usesEH() : 0;
 }
 
+int WhileStatement::blockExit()
+{
+    //printf("WhileStatement::blockExit(%p)\n", this);
+
+    int result = BEnone;
+    if (condition->canThrow())
+	result |= BEthrow;
+    if (condition->isBool(TRUE))
+    {
+	if (body)
+	{   result |= body->blockExit();
+	    if (result & BEbreak)
+		result |= BEfallthru;
+	}
+    }
+    else if (condition->isBool(FALSE))
+    {
+	result |= BEfallthru;
+    }
+    else
+    {
+	if (body)
+	    result |= body->blockExit();
+	result |= BEfallthru;
+    }
+    result &= ~(BEbreak | BEcontinue);
+    return result;
+}
+
 int WhileStatement::fallOffEnd()
 {
     if (body)
@@ -917,6 +1020,28 @@
     return body ? body->usesEH() : 0;
 }
 
+int DoStatement::blockExit()
+{   int result;
+
+    if (body)
+    {	result = body->blockExit();
+	if (result == BEbreak)
+	    return BEfallthru;
+	if (result & BEcontinue)
+	    result |= BEfallthru;
+    }
+    else
+	result = BEfallthru;
+    if (result & BEfallthru)
+    {	if (condition->canThrow())
+	    result |= BEthrow;
+	if (!(result & BEbreak) && condition->isBool(TRUE))
+	    result &= ~BEfallthru;
+    }
+    result &= ~(BEbreak | BEcontinue);
+    return result;
+}
+
 int DoStatement::fallOffEnd()
 {
     if (body)
@@ -1024,6 +1149,31 @@
     return (init && init->usesEH()) || body->usesEH();
 }
 
+int ForStatement::blockExit()
+{   int result = BEfallthru;
+
+    if (init)
+    {	result = init->blockExit();
+	if (!(result & BEfallthru))
+	    return result;
+    }
+    if (condition)
+    {	if (condition->canThrow())
+	    result |= BEthrow;
+    }
+    else
+	result &= ~BEfallthru;	// the body must do the exiting
+    if (body)
+    {	int r = body->blockExit();
+	if (r & BEbreak)
+	    result |= BEfallthru;
+	result |= r & ~(BEbreak | BEcontinue);
+    }
+    if (increment && increment->canThrow())
+	result |= BEthrow;
+    return result;
+}
+
 int ForStatement::fallOffEnd()
 {
     if (body)
@@ -1216,10 +1366,6 @@
 		    VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
 		    if (e->isConst())
 			v->storage_class |= STCconst;
-#if V2
-		    else
-			v->storage_class |= STCfinal;
-#endif
 		    var = v;
 		}
 	    }
@@ -1589,6 +1735,19 @@
     return body->usesEH();
 }
 
+int ForeachStatement::blockExit()
+{   int result = BEfallthru;
+
+    if (aggr->canThrow())
+	result |= BEthrow;
+
+    if (body)
+    {
+	result |= body->blockExit() & ~(BEbreak | BEcontinue);
+    }
+    return result;
+}
+
 int ForeachStatement::fallOffEnd()
 {
     if (body)
@@ -1607,7 +1766,6 @@
 {
     buf->writestring(Token::toChars(op));
     buf->writestring(" (");
-    int i;
     for (int i = 0; i < arguments->dim; i++)
     {
 	Argument *a = (Argument *)arguments->data[i];
@@ -1718,6 +1876,42 @@
     return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
 }
 
+int IfStatement::blockExit()
+{
+    //printf("IfStatement::blockExit(%p)\n", this);
+
+    int result = BEnone;
+    if (condition->canThrow())
+	result |= BEthrow;
+    if (condition->isBool(TRUE))
+    {
+	if (ifbody)
+	    result |= ifbody->blockExit();
+	else
+	    result |= BEfallthru;
+    }
+    else if (condition->isBool(FALSE))
+    {
+	if (elsebody)
+	    result |= elsebody->blockExit();
+	else
+	    result |= BEfallthru;
+    }
+    else
+    {
+	if (ifbody)
+	    result |= ifbody->blockExit();
+	else
+	    result |= BEfallthru;
+	if (elsebody)
+	    result |= elsebody->blockExit();
+	else
+	    result |= BEfallthru;
+    }
+    //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
+    return result;
+}
+
 int IfStatement::fallOffEnd()
 {
     if (!ifbody || ifbody->fallOffEnd() ||
@@ -1812,13 +2006,21 @@
 {
     condition->toCBuffer(buf, hgs);
     buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
     if (ifbody)
 	ifbody->toCBuffer(buf, hgs);
+    buf->writeByte('}');
+    buf->writenl();
     if (elsebody)
     {
 	buf->writestring("else");
 	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
 	elsebody->toCBuffer(buf, hgs);
+	buf->writeByte('}');
+	buf->writenl();
     }
     buf->writenl();
 }
@@ -1908,6 +2110,18 @@
     return body && body->usesEH();
 }
 
+int PragmaStatement::blockExit()
+{
+    int result = BEfallthru;
+#if 0 // currently, no code is generated for Pragma's, so it's just fallthru
+    if (arrayExpressionCanThrow(args))
+	result |= BEthrow;
+    if (body)
+	result |= body->blockExit();
+#endif
+    return result;
+}
+
 int PragmaStatement::fallOffEnd()
 {
     if (body)
@@ -2097,6 +2311,24 @@
     return body ? body->usesEH() : 0;
 }
 
+int SwitchStatement::blockExit()
+{   int result = BEnone;
+    if (condition->canThrow())
+	result |= BEthrow;
+
+    if (body)
+    {	result |= body->blockExit();
+	if (result & BEbreak)
+	{   result |= BEfallthru;
+	    result &= ~BEbreak;
+	}
+    }
+    else
+	result |= BEfallthru;
+
+    return result;
+}
+
 int SwitchStatement::fallOffEnd()
 {
     if (body)
@@ -2204,6 +2436,11 @@
     return statement->usesEH();
 }
 
+int CaseStatement::blockExit()
+{
+    return statement->blockExit();
+}
+
 int CaseStatement::fallOffEnd()
 {
     return statement->fallOffEnd();
@@ -2243,6 +2480,7 @@
 
 Statement *DefaultStatement::semantic(Scope *sc)
 {
+    //printf("DefaultStatement::semantic()\n");
     if (sc->sw)
     {
 	if (sc->sw->sdefault)
@@ -2262,6 +2500,11 @@
     return statement->usesEH();
 }
 
+int DefaultStatement::blockExit()
+{
+    return statement->blockExit();
+}
+
 int DefaultStatement::fallOffEnd()
 {
     return statement->fallOffEnd();
@@ -2302,6 +2545,11 @@
     return this;
 }
 
+int GotoDefaultStatement::blockExit()
+{
+    return BEgoto;
+}
+
 int GotoDefaultStatement::fallOffEnd()
 {
     return FALSE;
@@ -2351,6 +2599,11 @@
     return this;
 }
 
+int GotoCaseStatement::blockExit()
+{
+    return BEgoto;
+}
+
 int GotoCaseStatement::fallOffEnd()
 {
     return FALSE;
@@ -2374,6 +2627,11 @@
 {
 }
 
+int SwitchErrorStatement::blockExit()
+{
+    return BEthrow;
+}
+
 int SwitchErrorStatement::fallOffEnd()
 {
     return FALSE;
@@ -2427,6 +2685,8 @@
 
     Type *tret = fd->type->nextOf();
     if (fd->tintro)
+	/* We'll be implicitly casting the return expression to tintro
+	 */
 	tret = fd->tintro->nextOf();
     Type *tbret = NULL;
 
@@ -2636,9 +2896,13 @@
     }
 
     if (exp && tbret->ty == Tvoid && !fd->isMain())
-    {   Statement *s;
-
-	s = new ExpStatement(loc, exp);
+    {
+	/* Replace:
+	 *	return exp;
+	 * with:
+	 *	exp; return;
+	 */
+	Statement *s = new ExpStatement(loc, exp);
 	loc = 0;
 	exp = NULL;
 	return new CompoundStatement(loc, s, this);
@@ -2647,6 +2911,14 @@
     return this;
 }
 
+int ReturnStatement::blockExit()
+{   int result = BEreturn;
+
+    if (exp && exp->canThrow())
+	result |= BEthrow;
+    return result;
+}
+
 int ReturnStatement::fallOffEnd()
 {
     return FALSE;
@@ -2678,6 +2950,7 @@
 
 Statement *BreakStatement::semantic(Scope *sc)
 {
+    //printf("BreakStatement::semantic()\n");
     enclosinghandler = sc->tfOfTry;
     // If:
     //	break Identifier;
@@ -2739,6 +3012,12 @@
     return this;
 }
 
+int BreakStatement::blockExit()
+{
+    //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
+    return ident ? BEgoto : BEbreak;
+}
+
 int BreakStatement::fallOffEnd()
 {
     return FALSE;
@@ -2842,6 +3121,11 @@
     return this;
 }
 
+int ContinueStatement::blockExit()
+{
+    return ident ? BEgoto : BEcontinue;
+}
+
 int ContinueStatement::fallOffEnd()
 {
     return FALSE;
@@ -2932,6 +3216,11 @@
     return TRUE;
 }
 
+int SynchronizedStatement::blockExit()
+{
+    return body ? body->blockExit() : BEfallthru;
+}
+
 int SynchronizedStatement::fallOffEnd()
 {
     return body ? body->fallOffEnd() : TRUE;
@@ -3042,6 +3331,18 @@
     return body ? body->usesEH() : 0;
 }
 
+int WithStatement::blockExit()
+{
+    int result = BEnone;
+    if (exp->canThrow())
+	result = BEthrow;
+    if (body)
+	result |= body->blockExit();
+    else
+	result |= BEfallthru;
+    return result;
+}
+
 int WithStatement::fallOffEnd()
 {
     return body ? body->fallOffEnd() : TRUE;
@@ -3075,14 +3376,14 @@
 {
     body = body->semanticScope(sc, NULL /*this*/, NULL);
 
-    for (int i = 0; i < catches->dim; i++)
-    {   Catch *c;
-
-	c = (Catch *)catches->data[i];
+    /* Even if body is NULL, still do semantic analysis on catches
+     */
+    for (size_t i = 0; i < catches->dim; i++)
+    {   Catch *c = (Catch *)catches->data[i];
 	c->semantic(sc);
 
 	// Determine if current catch 'hides' any previous catches
-	for (int j = 0; j < i; j++)
+	for (size_t j = 0; j < i; j++)
 	{   Catch *cj = (Catch *)catches->data[j];
 	    char *si = c->loc.toChars();
 	    char *sj = cj->loc.toChars();
@@ -3104,6 +3405,20 @@
     return TRUE;
 }
 
+int TryCatchStatement::blockExit()
+{   int result;
+
+    assert(body);
+    result = body->blockExit();
+
+    for (size_t i = 0; i < catches->dim; i++)
+    {
+        Catch *c = (Catch *)catches->data[i];
+        result |= c->blockExit();
+    }
+    return result;
+}
+
 int TryCatchStatement::fallOffEnd()
 {
     int result = FALSE;
@@ -3126,8 +3441,7 @@
     buf->writenl();
     if (body)
         body->toCBuffer(buf, hgs);
-    int i;
-    for (i = 0; i < catches->dim; i++)
+    for (size_t i = 0; i < catches->dim; i++)
     {
         Catch *c = (Catch *)catches->data[i];
         c->toCBuffer(buf, hgs);
@@ -3193,6 +3507,11 @@
     sc->pop();
 }
 
+int Catch::blockExit()
+{
+    return handler ? handler->blockExit() : BEfallthru;
+}
+
 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("catch");
@@ -3204,7 +3523,8 @@
     buf->writenl();
     buf->writebyte('{');
     buf->writenl();
-    handler->toCBuffer(buf, hgs);
+    if (handler)
+	handler->toCBuffer(buf, hgs);
     buf->writebyte('}');
     buf->writenl();
 }
@@ -3269,6 +3589,12 @@
     return TRUE;
 }
 
+int TryFinallyStatement::blockExit()
+{
+    int result = body->blockExit();
+    return result;
+}
+
 int TryFinallyStatement::fallOffEnd()
 {   int result;
 
@@ -3300,6 +3626,11 @@
     return this;
 }
 
+int OnScopeStatement::blockExit()
+{   // At this point, this statement is just an empty placeholder
+    return BEfallthru;
+}
+
 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring(Token::toChars(tok));
@@ -3391,6 +3722,11 @@
     return this;
 }
 
+int ThrowStatement::blockExit()
+{
+    return BEthrow;  // obviously
+}
+
 int ThrowStatement::fallOffEnd()
 {
     return FALSE;
@@ -3449,6 +3785,11 @@
     return a;
 }
 
+int VolatileStatement::blockExit()
+{
+    return statement ? statement->blockExit() : BEfallthru;
+}
+
 int VolatileStatement::fallOffEnd()
 {
     return statement ? statement->fallOffEnd() : TRUE;
@@ -3512,6 +3853,12 @@
     return this;
 }
 
+int GotoStatement::blockExit()
+{
+    //printf("GotoStatement::blockExit(%p)\n", this);
+    return BEgoto;
+}
+
 int GotoStatement::fallOffEnd()
 {
     return FALSE;
@@ -3601,6 +3948,12 @@
     return statement ? statement->usesEH() : FALSE;
 }
 
+int LabelStatement::blockExit()
+{
+    //printf("LabelStatement::blockExit(%p)\n", this);
+    return statement ? statement->blockExit() : BEfallthru;
+}
+
 int LabelStatement::fallOffEnd()
 {
     return statement ? statement->fallOffEnd() : TRUE;
--- a/dmd/statement.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/statement.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,848 +1,926 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#ifndef DMD_STATEMENT_H
-#define DMD_STATEMENT_H
-
-#ifdef __DMC__
-#pragma once
-#endif /* __DMC__ */
-
-#include "root.h"
-
-#include "arraytypes.h"
-#include "dsymbol.h"
-#include "lexer.h"
-
-struct OutBuffer;
-struct Scope;
-struct Expression;
-struct LabelDsymbol;
-struct Identifier;
-struct IfStatement;
-struct DeclarationStatement;
-struct DefaultStatement;
-struct VarDeclaration;
-struct Condition;
-struct Module;
-struct Token;
-struct InlineCostState;
-struct InlineDoState;
-struct InlineScanState;
-struct ReturnStatement;
-struct CompoundStatement;
-struct Argument;
-struct StaticAssert;
-struct AsmStatement;
-struct AsmBlockStatement;
-struct GotoStatement;
-struct ScopeStatement;
-struct TryCatchStatement;
-struct TryFinallyStatement;
-struct HdrGenState;
-struct InterState;
-struct CaseStatement;
-struct LabelStatement;
-struct VolatileStatement;
-struct SynchronizedStatement;
-
-enum TOK;
-
-namespace llvm
-{
-    class Value;
-    class BasicBlock;
-    class ConstantInt;
-}
-
-// Back end
-struct IRState;
-struct Blockx;
-#if IN_LLVM
-struct DValue;
-typedef DValue elem;
-#endif
-
-#if IN_GCC
-union tree_node; typedef union tree_node block;
-//union tree_node; typedef union tree_node elem;
-#else
-struct block;
-//struct elem;
-#endif
-struct code;
-
-// LLVMDC this is used for tracking try-finally, synchronized and volatile scopes
-// definitions in gen/llvmhelpers.cpp
-struct EnclosingHandler : Object
-{
-    virtual void emitCode(IRState* p) = 0;
-    virtual EnclosingHandler* getEnclosing() = 0;
-};
-struct EnclosingTryFinally : EnclosingHandler
-{
-    TryFinallyStatement* tf;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {}
-};
-struct EnclosingVolatile : EnclosingHandler
-{
-    VolatileStatement* v;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {}
-};
-struct EnclosingSynchro : EnclosingHandler
-{
-    SynchronizedStatement* s;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {}
-};
-
-struct Statement : Object
-{
-    Loc loc;
-
-    Statement(Loc loc);
-    virtual Statement *syntaxCopy();
-
-    void print();
-    char *toChars();
-
-    void error(const char *format, ...);
-    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    virtual TryCatchStatement *isTryCatchStatement() { return NULL; }
-    virtual GotoStatement *isGotoStatement() { return NULL; }
-    virtual AsmStatement *isAsmStatement() { return NULL; }
-    virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; }
-#ifdef _DH
-    int incontract;
-#endif
-    virtual ScopeStatement *isScopeStatement() { return NULL; }
-    virtual Statement *semantic(Scope *sc);
-    Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue);
-    virtual int hasBreak();
-    virtual int hasContinue();
-    virtual int usesEH();
-    virtual int fallOffEnd();
-    virtual int comeFrom();
-    virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
-    virtual Statements *flatten(Scope *sc);
-    virtual Expression *interpret(InterState *istate);
-
-    virtual int inlineCost(InlineCostState *ics);
-    virtual Expression *doInline(InlineDoState *ids);
-    virtual Statement *inlineScan(InlineScanState *iss);
-
-    // Back end
-    virtual void toIR(IRState *irs);
-
-    // Avoid dynamic_cast
-    virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
-    virtual CompoundStatement *isCompoundStatement() { return NULL; }
-    virtual ReturnStatement *isReturnStatement() { return NULL; }
-    virtual IfStatement *isIfStatement() { return NULL; }
-    virtual CaseStatement* isCaseStatement() { return NULL; }
-};
-
-struct ExpStatement : Statement
-{
-    Expression *exp;
-
-    ExpStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    int fallOffEnd();
-
-    int inlineCost(InlineCostState *ics);
-    Expression *doInline(InlineDoState *ids);
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct CompileStatement : Statement
-{
-    Expression *exp;
-
-    CompileStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-};
-
-struct DeclarationStatement : ExpStatement
-{
-    // Doing declarations as an expression, rather than a statement,
-    // makes inlining functions much easier.
-
-    DeclarationStatement(Loc loc, Dsymbol *s);
-    DeclarationStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
-
-    DeclarationStatement *isDeclarationStatement() { return this; }
-};
-
-struct CompoundStatement : Statement
-{
-    Statements *statements;
-
-    CompoundStatement(Loc loc, Statements *s);
-    CompoundStatement(Loc loc, Statement *s1, Statement *s2);
-    virtual Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    virtual Statements *flatten(Scope *sc);
-    ReturnStatement *isReturnStatement();
-    Expression *interpret(InterState *istate);
-
-    int inlineCost(InlineCostState *ics);
-    Expression *doInline(InlineDoState *ids);
-    Statement *inlineScan(InlineScanState *iss);
-
-    virtual void toIR(IRState *irs);
-
-    virtual CompoundStatement *isCompoundStatement() { return this; }
-};
-
-/* The purpose of this is so that continue will go to the next
- * of the statements, and break will go to the end of the statements.
- */
-struct UnrolledLoopStatement : Statement
-{
-    Statements *statements;
-    EnclosingHandler* enclosinghandler;
-
-    UnrolledLoopStatement(Loc loc, Statements *statements);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    int inlineCost(InlineCostState *ics);
-    Expression *doInline(InlineDoState *ids);
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct ScopeStatement : Statement
-{
-    Statement *statement;
-
-    ScopeStatement(Loc loc, Statement *s);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    ScopeStatement *isScopeStatement() { return this; }
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct WhileStatement : Statement
-{
-    Expression *condition;
-    Statement *body;
-    EnclosingHandler* enclosinghandler;
-
-    WhileStatement(Loc loc, Expression *c, Statement *b);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct DoStatement : Statement
-{
-    Statement *body;
-    Expression *condition;
-    EnclosingHandler* enclosinghandler;
-
-    DoStatement(Loc loc, Statement *b, Expression *c);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct ForStatement : Statement
-{
-    Statement *init;
-    Expression *condition;
-    Expression *increment;
-    Statement *body;
-    EnclosingHandler* enclosinghandler;
-
-    ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct ForeachStatement : Statement
-{
-    enum TOK op;	// TOKforeach or TOKforeach_reverse
-    Arguments *arguments;	// array of Argument*'s
-    Expression *aggr;
-    Statement *body;
-    EnclosingHandler* enclosinghandler;
-
-    VarDeclaration *key;
-    VarDeclaration *value;
-
-    FuncDeclaration *func;	// function we're lexically in
-
-    Array cases;	// put breaks, continues, gotos and returns here
-    Array gotos;	// forward referenced goto's go here
-
-    ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct IfStatement : Statement
-{
-    Argument *arg;
-    Expression *condition;
-    Statement *ifbody;
-    Statement *elsebody;
-
-    VarDeclaration *match;	// for MatchExpression results
-
-    IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    int usesEH();
-    int fallOffEnd();
-    IfStatement *isIfStatement() { return this; }
-
-    int inlineCost(InlineCostState *ics);
-    Expression *doInline(InlineDoState *ids);
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct ConditionalStatement : Statement
-{
-    Condition *condition;
-    Statement *ifbody;
-    Statement *elsebody;
-
-    ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Statements *flatten(Scope *sc);
-    int usesEH();
-
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-};
-
-struct PragmaStatement : Statement
-{
-    Identifier *ident;
-    Expressions *args;		// array of Expression's
-    Statement *body;
-
-    PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int usesEH();
-    int fallOffEnd();
-
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-};
-
-struct StaticAssertStatement : Statement
-{
-    StaticAssert *sa;
-
-    StaticAssertStatement(StaticAssert *sa);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-};
-
-struct SwitchStatement : Statement
-{
-    Expression *condition;
-    Statement *body;
-    DefaultStatement *sdefault;
-    EnclosingHandler* enclosinghandler;
-
-    Array gotoCases;		// array of unresolved GotoCaseStatement's
-    Array *cases;		// array of CaseStatement's
-    int hasNoDefault;		// !=0 if no default statement
-
-    SwitchStatement(Loc loc, Expression *c, Statement *b);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int usesEH();
-    int fallOffEnd();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct CaseStatement : Statement
-{
-    Expression *exp;
-    Statement *statement;
-    int index;		// which case it is (since we sort this)
-    block *cblock;	// back end: label for the block
-
-    CaseStatement(Loc loc, Expression *exp, Statement *s);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int compare(Object *obj);
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-
-    CaseStatement* isCaseStatement() { return this; }
-
-    // LLVMDC
-    llvm::BasicBlock* bodyBB;
-    llvm::ConstantInt* llvmIdx;
-};
-
-struct DefaultStatement : Statement
-{
-    Statement *statement;
-#if IN_GCC
-    block *cblock;	// back end: label for the block
-#endif
-
-    DefaultStatement(Loc loc, Statement *s);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-
-    // LLVMDC
-    llvm::BasicBlock* bodyBB;
-};
-
-struct GotoDefaultStatement : Statement
-{
-    SwitchStatement *sw;
-    EnclosingHandler* enclosinghandler;
-
-    GotoDefaultStatement(Loc loc);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    void toIR(IRState *irs);
-};
-
-struct GotoCaseStatement : Statement
-{
-    Expression *exp;		// NULL, or which case to goto
-    CaseStatement *cs;		// case statement it resolves to
-    EnclosingHandler* enclosinghandler;
-    SwitchStatement *sw;
-
-    GotoCaseStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    void toIR(IRState *irs);
-};
-
-struct SwitchErrorStatement : Statement
-{
-    SwitchErrorStatement(Loc loc);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    void toIR(IRState *irs);
-};
-
-struct ReturnStatement : Statement
-{
-    Expression *exp;
-    EnclosingHandler* enclosinghandler;
-
-    ReturnStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-    int fallOffEnd();
-    Expression *interpret(InterState *istate);
-
-    int inlineCost(InlineCostState *ics);
-    Expression *doInline(InlineDoState *ids);
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-
-    ReturnStatement *isReturnStatement() { return this; }
-};
-
-struct BreakStatement : Statement
-{
-    Identifier *ident;
-    EnclosingHandler* enclosinghandler;
-
-    BreakStatement(Loc loc, Identifier *ident);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    void toIR(IRState *irs);
-
-    // LLVMDC: only set if ident is set: label statement to jump to
-    LabelStatement *target;
-};
-
-struct ContinueStatement : Statement
-{
-    Identifier *ident;
-    EnclosingHandler* enclosinghandler;
-
-    ContinueStatement(Loc loc, Identifier *ident);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Expression *interpret(InterState *istate);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    void toIR(IRState *irs);
-
-    // LLVMDC: only set if ident is set: label statement to jump to
-    LabelStatement *target;
-};
-
-struct SynchronizedStatement : Statement
-{
-    Expression *exp;
-    Statement *body;
-    EnclosingHandler* enclosinghandler;
-
-    SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-// Back end
-    elem *esync;
-    SynchronizedStatement(Loc loc, elem *esync, Statement *body);
-    void toIR(IRState *irs);
-    llvm::Value* llsync;
-};
-
-struct WithStatement : Statement
-{
-    Expression *exp;
-    Statement *body;
-    VarDeclaration *wthis;
-
-    WithStatement(Loc loc, Expression *exp, Statement *body);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    int usesEH();
-    int fallOffEnd();
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct TryCatchStatement : Statement
-{
-    Statement *body;
-    Array *catches;
-
-    TryCatchStatement(Loc loc, Statement *body, Array *catches);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int usesEH();
-    int fallOffEnd();
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    TryCatchStatement *isTryCatchStatement() { return this; }
-};
-
-struct Catch : Object
-{
-    Loc loc;
-    Type *type;
-    Identifier *ident;
-    VarDeclaration *var;
-    Statement *handler;
-
-    Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
-    Catch *syntaxCopy();
-    void semantic(Scope *sc);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-};
-
-struct TryFinallyStatement : Statement
-{
-    Statement *body;
-    Statement *finalbody;
-    EnclosingHandler* enclosinghandler;
-
-    TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-    int hasBreak();
-    int hasContinue();
-    int usesEH();
-    int fallOffEnd();
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct OnScopeStatement : Statement
-{
-    TOK tok;
-    Statement *statement;
-
-    OnScopeStatement(Loc loc, TOK tok, Statement *statement);
-    Statement *syntaxCopy();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    Statement *semantic(Scope *sc);
-    int usesEH();
-    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
-
-    void toIR(IRState *irs);
-};
-
-struct ThrowStatement : Statement
-{
-    Expression *exp;
-
-    ThrowStatement(Loc loc, Expression *exp);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    int fallOffEnd();
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct VolatileStatement : Statement
-{
-    Statement *statement;
-    EnclosingHandler* enclosinghandler;
-
-    VolatileStatement(Loc loc, Statement *statement);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Statements *flatten(Scope *sc);
-    int fallOffEnd();
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-};
-
-struct GotoStatement : Statement
-{
-    Identifier *ident;
-    LabelDsymbol *label;
-    TryFinallyStatement *tf;
-    EnclosingHandler* enclosinghandler;
-
-    GotoStatement(Loc loc, Identifier *ident);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int fallOffEnd();
-    Expression *interpret(InterState *istate);
-
-    void toIR(IRState *irs);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    GotoStatement *isGotoStatement() { return this; }
-};
-
-struct LabelStatement : Statement
-{
-    Identifier *ident;
-    Statement *statement;
-    TryFinallyStatement *tf;
-    EnclosingHandler* enclosinghandler;
-    block *lblock;		// back end
-    int isReturnLabel;
-
-    LabelStatement(Loc loc, Identifier *ident, Statement *statement);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    Statements *flatten(Scope *sc);
-    int usesEH();
-    int fallOffEnd();
-    int comeFrom();
-    Expression *interpret(InterState *istate);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-
-    Statement *inlineScan(InlineScanState *iss);
-
-    void toIR(IRState *irs);
-
-    // LLVMDC
-    llvm::BasicBlock* llvmBB;
-    bool asmLabel;       // for labels inside inline assembler
-};
-
-struct LabelDsymbol : Dsymbol
-{
-    LabelStatement *statement;
-
-    LabelDsymbol(Identifier *ident);
-    LabelDsymbol *isLabel();
-};
-
-struct AsmStatement : Statement
-{
-    Token *tokens;
-    code *asmcode;
-    unsigned asmalign;		// alignment of this statement
-    unsigned refparam;		// !=0 if function parameter is referenced
-    unsigned naked;		// !=0 if function is to be naked
-    unsigned regs;		// mask of registers modified
-
-    AsmStatement(Loc loc, Token *tokens);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-    int comeFrom();
-
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    virtual AsmStatement *isAsmStatement() { return this; }
-
-    void toIR(IRState *irs);
-
-    // LLVMDC
-    // non-zero if this is a branch, contains the target labels identifier
-    Identifier* isBranchToLabel;
-};
-
-struct AsmBlockStatement : CompoundStatement
-{
-    EnclosingHandler* enclosinghandler;
-
-    AsmBlockStatement(Loc loc, Statements *s);
-    Statements *flatten(Scope *sc);
-    Statement *syntaxCopy();
-    Statement *semantic(Scope *sc);
-
-    CompoundStatement *isCompoundStatement() { return NULL; }
-    AsmBlockStatement *isAsmBlockStatement() { return this; }
-
-    void toIR(IRState *irs);
-};
-
-#endif /* DMD_STATEMENT_H */
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_STATEMENT_H
+#define DMD_STATEMENT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+
+#include "arraytypes.h"
+#include "dsymbol.h"
+#include "lexer.h"
+
+struct OutBuffer;
+struct Scope;
+struct Expression;
+struct LabelDsymbol;
+struct Identifier;
+struct IfStatement;
+struct DeclarationStatement;
+struct DefaultStatement;
+struct VarDeclaration;
+struct Condition;
+struct Module;
+struct Token;
+struct InlineCostState;
+struct InlineDoState;
+struct InlineScanState;
+struct ReturnStatement;
+struct CompoundStatement;
+struct Argument;
+struct StaticAssert;
+struct AsmStatement;
+struct AsmBlockStatement;
+struct GotoStatement;
+struct ScopeStatement;
+struct TryCatchStatement;
+struct TryFinallyStatement;
+struct HdrGenState;
+struct InterState;
+struct CaseStatement;
+struct LabelStatement;
+struct VolatileStatement;
+struct SynchronizedStatement;
+
+enum TOK;
+
+namespace llvm
+{
+    class Value;
+    class BasicBlock;
+    class ConstantInt;
+}
+
+// Back end
+struct IRState;
+struct Blockx;
+#if IN_LLVM
+struct DValue;
+typedef DValue elem;
+#endif
+
+#if IN_GCC
+union tree_node; typedef union tree_node block;
+//union tree_node; typedef union tree_node elem;
+#else
+struct block;
+//struct elem;
+#endif
+struct code;
+
+/* How a statement exits
+ */
+enum BE
+{
+    BEnone =	 0,
+    BEfallthru = 1,
+    BEthrow =    2,
+    BEreturn =   4,
+    BEgoto =     8,
+    BEhalt =	 0x10,
+    BEbreak =	 0x20,
+    BEcontinue = 0x40,
+    BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt),
+};
+
+// LLVMDC this is used for tracking try-finally, synchronized and volatile scopes
+// definitions in gen/llvmhelpers.cpp
+struct EnclosingHandler : Object
+{
+    virtual void emitCode(IRState* p) = 0;
+    virtual EnclosingHandler* getEnclosing() = 0;
+};
+struct EnclosingTryFinally : EnclosingHandler
+{
+    TryFinallyStatement* tf;
+    void emitCode(IRState* p);
+    EnclosingHandler* getEnclosing();
+    EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {}
+};
+struct EnclosingVolatile : EnclosingHandler
+{
+    VolatileStatement* v;
+    void emitCode(IRState* p);
+    EnclosingHandler* getEnclosing();
+    EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {}
+};
+struct EnclosingSynchro : EnclosingHandler
+{
+    SynchronizedStatement* s;
+    void emitCode(IRState* p);
+    EnclosingHandler* getEnclosing();
+    EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {}
+};
+
+struct Statement : Object
+{
+    Loc loc;
+
+    Statement(Loc loc);
+    virtual Statement *syntaxCopy();
+
+    void print();
+    char *toChars();
+
+    void error(const char *format, ...);
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual TryCatchStatement *isTryCatchStatement() { return NULL; }
+    virtual GotoStatement *isGotoStatement() { return NULL; }
+    virtual AsmStatement *isAsmStatement() { return NULL; }
+    virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; }
+#ifdef _DH
+    int incontract;
+#endif
+    virtual ScopeStatement *isScopeStatement() { return NULL; }
+    virtual Statement *semantic(Scope *sc);
+    Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue);
+    virtual int hasBreak();
+    virtual int hasContinue();
+    virtual int usesEH();
+    virtual int fallOffEnd();
+    virtual int blockExit();
+    virtual int comeFrom();
+    virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+    virtual Statements *flatten(Scope *sc);
+    virtual Expression *interpret(InterState *istate);
+
+    virtual int inlineCost(InlineCostState *ics);
+    virtual Expression *doInline(InlineDoState *ids);
+    virtual Statement *inlineScan(InlineScanState *iss);
+
+    // Back end
+    virtual void toIR(IRState *irs);
+
+    // Avoid dynamic_cast
+    virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
+    virtual CompoundStatement *isCompoundStatement() { return NULL; }
+    virtual ReturnStatement *isReturnStatement() { return NULL; }
+    virtual IfStatement *isIfStatement() { return NULL; }
+    virtual CaseStatement* isCaseStatement() { return NULL; }
+};
+
+struct ExpStatement : Statement
+{
+    Expression *exp;
+
+    ExpStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+    int blockExit();
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct CompileStatement : Statement
+{
+    Expression *exp;
+
+    CompileStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statements *flatten(Scope *sc);
+    Statement *semantic(Scope *sc);
+};
+
+struct DeclarationStatement : ExpStatement
+{
+    // Doing declarations as an expression, rather than a statement,
+    // makes inlining functions much easier.
+
+    DeclarationStatement(Loc loc, Dsymbol *s);
+    DeclarationStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    DeclarationStatement *isDeclarationStatement() { return this; }
+};
+
+struct CompoundStatement : Statement
+{
+    Statements *statements;
+
+    CompoundStatement(Loc loc, Statements *s);
+    CompoundStatement(Loc loc, Statement *s1, Statement *s2);
+    virtual Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual Statement *semantic(Scope *sc);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    virtual Statements *flatten(Scope *sc);
+    ReturnStatement *isReturnStatement();
+    Expression *interpret(InterState *istate);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    virtual void toIR(IRState *irs);
+
+    virtual CompoundStatement *isCompoundStatement() { return this; }
+};
+
+/* The purpose of this is so that continue will go to the next
+ * of the statements, and break will go to the end of the statements.
+ */
+struct UnrolledLoopStatement : Statement
+{
+    Statements *statements;
+    EnclosingHandler* enclosinghandler;
+
+    UnrolledLoopStatement(Loc loc, Statements *statements);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ScopeStatement : Statement
+{
+    Statement *statement;
+
+    ScopeStatement(Loc loc, Statement *s);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    ScopeStatement *isScopeStatement() { return this; }
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct WhileStatement : Statement
+{
+    Expression *condition;
+    Statement *body;
+    EnclosingHandler* enclosinghandler;
+
+    WhileStatement(Loc loc, Expression *c, Statement *b);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct DoStatement : Statement
+{
+    Statement *body;
+    Expression *condition;
+    EnclosingHandler* enclosinghandler;
+
+    DoStatement(Loc loc, Statement *b, Expression *c);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ForStatement : Statement
+{
+    Statement *init;
+    Expression *condition;
+    Expression *increment;
+    Statement *body;
+    EnclosingHandler* enclosinghandler;
+
+    ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ForeachStatement : Statement
+{
+    enum TOK op;		// TOKforeach or TOKforeach_reverse
+    Arguments *arguments;	// array of Argument*'s
+    Expression *aggr;
+    Statement *body;
+    EnclosingHandler* enclosinghandler;
+
+    VarDeclaration *key;
+    VarDeclaration *value;
+
+    FuncDeclaration *func;	// function we're lexically in
+
+    Array cases;	// put breaks, continues, gotos and returns here
+    Array gotos;	// forward referenced goto's go here
+
+    ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+#if DMDV2
+struct ForeachRangeStatement : Statement
+{
+    enum TOK op;		// TOKforeach or TOKforeach_reverse
+    Argument *arg;		// loop index variable
+    Expression *lwr;
+    Expression *upr;
+    Statement *body;
+
+    VarDeclaration *key;
+
+    ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg,
+	Expression *lwr, Expression *upr, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+#endif
+
+struct IfStatement : Statement
+{
+    Argument *arg;
+    Expression *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+
+    VarDeclaration *match;	// for MatchExpression results
+
+    IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    IfStatement *isIfStatement() { return this; }
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ConditionalStatement : Statement
+{
+    Condition *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+
+    ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int usesEH();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct PragmaStatement : Statement
+{
+    Identifier *ident;
+    Expressions *args;		// array of Expression's
+    Statement *body;
+
+    PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticAssertStatement : Statement
+{
+    StaticAssert *sa;
+
+    StaticAssertStatement(StaticAssert *sa);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct SwitchStatement : Statement
+{
+    Expression *condition;
+    Statement *body;
+
+    DefaultStatement *sdefault;
+    EnclosingHandler* enclosinghandler;
+
+    Array gotoCases;		// array of unresolved GotoCaseStatement's
+    Array *cases;		// array of CaseStatement's
+    int hasNoDefault;		// !=0 if no default statement
+
+    SwitchStatement(Loc loc, Expression *c, Statement *b);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct CaseStatement : Statement
+{
+    Expression *exp;
+    Statement *statement;
+    int index;		// which case it is (since we sort this)
+    block *cblock;	// back end: label for the block
+
+    CaseStatement(Loc loc, Expression *exp, Statement *s);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int compare(Object *obj);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    CaseStatement* isCaseStatement() { return this; }
+
+    // LLVMDC
+    llvm::BasicBlock* bodyBB;
+    llvm::ConstantInt* llvmIdx;
+};
+
+struct DefaultStatement : Statement
+{
+    Statement *statement;
+#if IN_GCC
+    block *cblock;	// back end: label for the block
+#endif
+
+    DefaultStatement(Loc loc, Statement *s);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    // LLVMDC
+    llvm::BasicBlock* bodyBB;
+};
+
+struct GotoDefaultStatement : Statement
+{
+    SwitchStatement *sw;
+    EnclosingHandler* enclosinghandler;
+
+    GotoDefaultStatement(Loc loc);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct GotoCaseStatement : Statement
+{
+    Expression *exp;		// NULL, or which case to goto
+    CaseStatement *cs;		// case statement it resolves to
+    EnclosingHandler* enclosinghandler;
+    SwitchStatement *sw;
+
+    GotoCaseStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct SwitchErrorStatement : Statement
+{
+    SwitchErrorStatement(Loc loc);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct ReturnStatement : Statement
+{
+    Expression *exp;
+    EnclosingHandler* enclosinghandler;
+
+    ReturnStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int blockExit();
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    ReturnStatement *isReturnStatement() { return this; }
+};
+
+struct BreakStatement : Statement
+{
+    Identifier *ident;
+    EnclosingHandler* enclosinghandler;
+
+    BreakStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+
+    // LLVMDC: only set if ident is set: label statement to jump to
+    LabelStatement *target;
+};
+
+struct ContinueStatement : Statement
+{
+    Identifier *ident;
+    EnclosingHandler* enclosinghandler;
+
+    ContinueStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+
+    // LLVMDC: only set if ident is set: label statement to jump to
+    LabelStatement *target;
+};
+
+struct SynchronizedStatement : Statement
+{
+    Expression *exp;
+    Statement *body;
+    EnclosingHandler* enclosinghandler;
+
+    SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+// Back end
+    elem *esync;
+    SynchronizedStatement(Loc loc, elem *esync, Statement *body);
+    void toIR(IRState *irs);
+    llvm::Value* llsync;
+};
+
+struct WithStatement : Statement
+{
+    Expression *exp;
+    Statement *body;
+    VarDeclaration *wthis;
+
+    WithStatement(Loc loc, Expression *exp, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct TryCatchStatement : Statement
+{
+    Statement *body;
+    Array *catches;
+
+    TryCatchStatement(Loc loc, Statement *body, Array *catches);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    TryCatchStatement *isTryCatchStatement() { return this; }
+};
+
+struct Catch : Object
+{
+    Loc loc;
+    Type *type;
+    Identifier *ident;
+    VarDeclaration *var;
+    Statement *handler;
+
+    Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
+    Catch *syntaxCopy();
+    void semantic(Scope *sc);
+    int blockExit();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct TryFinallyStatement : Statement
+{
+    Statement *body;
+    Statement *finalbody;
+    EnclosingHandler* enclosinghandler;
+
+    TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct OnScopeStatement : Statement
+{
+    TOK tok;
+    Statement *statement;
+
+    OnScopeStatement(Loc loc, TOK tok, Statement *statement);
+    Statement *syntaxCopy();
+    int blockExit();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    void toIR(IRState *irs);
+};
+
+struct ThrowStatement : Statement
+{
+    Expression *exp;
+
+    ThrowStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int blockExit();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct VolatileStatement : Statement
+{
+    Statement *statement;
+    EnclosingHandler* enclosinghandler;
+
+    VolatileStatement(Loc loc, Statement *statement);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int blockExit();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct GotoStatement : Statement
+{
+    Identifier *ident;
+    LabelDsymbol *label;
+    TryFinallyStatement *tf;
+    EnclosingHandler* enclosinghandler;
+
+    GotoStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int blockExit();
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+
+    void toIR(IRState *irs);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    GotoStatement *isGotoStatement() { return this; }
+};
+
+struct LabelStatement : Statement
+{
+    Identifier *ident;
+    Statement *statement;
+    TryFinallyStatement *tf;
+    EnclosingHandler* enclosinghandler;
+    block *lblock;		// back end
+    int isReturnLabel;
+
+    LabelStatement(Loc loc, Identifier *ident, Statement *statement);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int usesEH();
+    int blockExit();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    // LLVMDC
+    llvm::BasicBlock* llvmBB;
+    bool asmLabel;       // for labels inside inline assembler
+};
+
+struct LabelDsymbol : Dsymbol
+{
+    LabelStatement *statement;
+
+    LabelDsymbol(Identifier *ident);
+    LabelDsymbol *isLabel();
+};
+
+struct AsmStatement : Statement
+{
+    Token *tokens;
+    code *asmcode;
+    unsigned asmalign;		// alignment of this statement
+    unsigned refparam;		// !=0 if function parameter is referenced
+    unsigned naked;		// !=0 if function is to be naked
+    unsigned regs;		// mask of registers modified
+
+    AsmStatement(Loc loc, Token *tokens);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int blockExit();
+    int comeFrom();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual AsmStatement *isAsmStatement() { return this; }
+
+    void toIR(IRState *irs);
+
+    // LLVMDC
+    // non-zero if this is a branch, contains the target labels identifier
+    Identifier* isBranchToLabel;
+};
+
+struct AsmBlockStatement : CompoundStatement
+{
+    EnclosingHandler* enclosinghandler;
+
+    AsmBlockStatement(Loc loc, Statements *s);
+    Statements *flatten(Scope *sc);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+
+    CompoundStatement *isCompoundStatement() { return NULL; }
+    AsmBlockStatement *isAsmBlockStatement() { return this; }
+
+    void toIR(IRState *irs);
+};
+
+#endif /* DMD_STATEMENT_H */
--- a/dmd/staticassert.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/staticassert.c	Sat Jul 12 19:38:31 2008 +0200
@@ -86,11 +86,11 @@
 {
 }
 
-void StaticAssert::toObjFile()
+void StaticAssert::toObjFile(int multiobj)
 {
 }
 
-char *StaticAssert::kind()
+const char *StaticAssert::kind()
 {
     return "static assert";
 }
--- a/dmd/staticassert.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/staticassert.h	Sat Jul 12 19:38:31 2008 +0200
@@ -35,8 +35,8 @@
     void semantic2(Scope *sc);
     void inlineScan();
     int oneMember(Dsymbol **ps);
-    void toObjFile();
-    char *kind();
+    void toObjFile(int multiobj);
+    const char *kind();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 };
 
--- a/dmd/stringtable.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/stringtable.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,8 +1,8 @@
 
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
-// www.digitalmars.com
+// http://www.digitalmars.com
 // License for redistribution is by either the Artistic License
 // in artistic.txt, or the GNU General Public License in gnu.txt.
 // See the included readme.txt for details.
--- a/dmd/stringtable.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/stringtable.h	Sat Jul 12 19:38:31 2008 +0200
@@ -1,7 +1,7 @@
-// Copyright (c) 1999-2002 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
-// www.digitalmars.com
+// http://www.digitalmars.com
 // License for redistribution is by either the Artistic License
 // in artistic.txt, or the GNU General Public License in gnu.txt.
 // See the included readme.txt for details.
--- a/dmd/struct.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/struct.c	Sat Jul 12 19:38:31 2008 +0200
@@ -254,6 +254,8 @@
     handle = type->pointerTo();
     structalign = sc->structalign;
     protection = sc->protection;
+    if (sc->stc & STCdeprecated)
+	isdeprecated = 1;
     assert(!isAnonymous());
     if (sc->stc & STCabstract)
 	error("structs, unions cannot be abstract");
@@ -450,7 +452,7 @@
 }
 
 
-char *StructDeclaration::kind()
+const char *StructDeclaration::kind()
 {
     return "struct";
 }
@@ -475,7 +477,7 @@
 }
 
 
-char *UnionDeclaration::kind()
+const char *UnionDeclaration::kind()
 {
     return "union";
 }
--- a/dmd/template.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/template.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,4159 +1,4296 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2008 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-// Handle template implementation
-
-#include <stdio.h>
-#include <assert.h>
-
-#if !IN_LLVM
-#if _WIN32
-#include <windows.h>
-long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
-#endif
-#endif
-
-#include "root.h"
-#include "mem.h"
-#include "stringtable.h"
-#include "mars.h"
-#include "identifier.h"
-#include "mtype.h"
-#include "template.h"
-#include "init.h"
-#include "expression.h"
-#include "scope.h"
-#include "module.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "dsymbol.h"
-#include "hdrgen.h"
-
-#define LOG	0
-
-/********************************************
- * These functions substitute for dynamic_cast. dynamic_cast does not work
- * on earlier versions of gcc.
- */
-
-Expression *isExpression(Object *o)
-{
-    //return dynamic_cast<Expression *>(o);
-    if (!o || o->dyncast() != DYNCAST_EXPRESSION)
-	return NULL;
-    return (Expression *)o;
-}
-
-Dsymbol *isDsymbol(Object *o)
-{
-    //return dynamic_cast<Dsymbol *>(o);
-    if (!o || o->dyncast() != DYNCAST_DSYMBOL)
-	return NULL;
-    return (Dsymbol *)o;
-}
-
-Type *isType(Object *o)
-{
-    //return dynamic_cast<Type *>(o);
-    if (!o || o->dyncast() != DYNCAST_TYPE)
-	return NULL;
-    return (Type *)o;
-}
-
-Tuple *isTuple(Object *o)
-{
-    //return dynamic_cast<Tuple *>(o);
-    if (!o || o->dyncast() != DYNCAST_TUPLE)
-	return NULL;
-    return (Tuple *)o;
-}
-
-
-/***********************
- * Try to get arg as a type.
- */
-
-Type *getType(Object *o)
-{
-    Type *t = isType(o);
-    if (!t)
-    {   Expression *e = isExpression(o);
-	if (e)
-	    t = e->type;
-    }
-    return t;
-}
-
-Dsymbol *getDsymbol(Object *oarg)
-{
-    Dsymbol *sa;
-    Expression *ea = isExpression(oarg);
-    if (ea)
-    {   // Try to convert Expression to symbol
-	if (ea->op == TOKvar)
-	    sa = ((VarExp *)ea)->var;
-	else if (ea->op == TOKfunction)
-	    sa = ((FuncExp *)ea)->fd;
-	else
-	    sa = NULL;
-    }
-    else
-    {   // Try to convert Type to symbol
-	Type *ta = isType(oarg);
-	if (ta)
-	    sa = ta->toDsymbol(NULL);
-	else
-	    sa = isDsymbol(oarg);	// if already a symbol
-    }
-    return sa;
-}
-
-/******************************
- * If o1 matches o2, return 1.
- * Else, return 0.
- */
-
-int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc)
-{
-    Type *t1 = isType(o1);
-    Type *t2 = isType(o2);
-    Expression *e1 = isExpression(o1);
-    Expression *e2 = isExpression(o2);
-    Dsymbol *s1 = isDsymbol(o1);
-    Dsymbol *s2 = isDsymbol(o2);
-    Tuple *v1 = isTuple(o1);
-    Tuple *v2 = isTuple(o2);
-    //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2);
-
-    /* A proper implementation of the various equals() overrides
-     * should make it possible to just do o1->equals(o2), but
-     * we'll do that another day.
-     */
-
-    if (t1)
-    {
-	/* if t1 is an instance of ti, then give error
-	 * about recursive expansions.
-	 */
-	Dsymbol *s = t1->toDsymbol(sc);
-	if (s && s->parent)
-	{   TemplateInstance *ti1 = s->parent->isTemplateInstance();
-	    if (ti1 && ti1->tempdecl == tempdecl)
-	    {
-		for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing)
-		{
-		    if (sc1->scopesym == ti1)
-		    {
-			error("recursive template expansion for template argument %s", t1->toChars());
-			return 1;	// fake a match
-		    }
-		}
-	    }
-	}
-
-	if (!t2 || !t1->equals(t2))
-	    goto Lnomatch;
-    }
-    else if (e1)
-    {
-#if 0
-	if (e1 && e2)
-	{
-	    printf("match %d\n", e1->equals(e2));
-	    e1->print();
-	    e2->print();
-	    e1->type->print();
-	    e2->type->print();
-	}
-#endif
-	if (!e2)
-	    goto Lnomatch;
-	if (!e1->equals(e2))
-	    goto Lnomatch;
-    }
-    else if (s1)
-    {
-	//printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars());
-	if (!s2 || !s1->equals(s2) || s1->parent != s2->parent)
-	{
-	    goto Lnomatch;
-	}
-    }
-    else if (v1)
-    {
-	if (!v2)
-	    goto Lnomatch;
-	if (v1->objects.dim != v2->objects.dim)
-	    goto Lnomatch;
-	for (size_t i = 0; i < v1->objects.dim; i++)
-	{
-	    if (!match((Object *)v1->objects.data[i],
-		       (Object *)v2->objects.data[i],
-		       tempdecl, sc))
-		goto Lnomatch;
-	}
-    }
-    return 1;	// match
-Lnomatch:
-    return 0;	// nomatch;
-}
-
-/****************************************
- */
-
-void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg)
-{
-    //printf("ObjectToCBuffer()\n");
-    Type *t = isType(oarg);
-    Expression *e = isExpression(oarg);
-    Dsymbol *s = isDsymbol(oarg);
-    Tuple *v = isTuple(oarg);
-    if (t)
-    {	//printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
-	t->toCBuffer(buf, NULL, hgs);
-    }
-    else if (e)
-	e->toCBuffer(buf, hgs);
-    else if (s)
-    {
-	char *p = s->ident ? s->ident->toChars() : s->toChars();
-	buf->writestring(p);
-    }
-    else if (v)
-    {
-	Objects *args = &v->objects;
-	for (size_t i = 0; i < args->dim; i++)
-	{
-	    if (i)
-		buf->writeByte(',');
-	    Object *o = (Object *)args->data[i];
-	    ObjectToCBuffer(buf, hgs, o);
-	}
-    }
-    else if (!oarg)
-    {
-	buf->writestring("NULL");
-    }
-    else
-    {
-#ifdef DEBUG
-	printf("bad Object = %p\n", oarg);
-#endif
-	assert(0);
-    }
-}
-
-
-
-/* ======================== TemplateDeclaration ============================= */
-
-TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs)
-    : ScopeDsymbol(id)
-{
-#if LOG
-    printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars());
-#endif
-#if 0
-    if (parameters)
-	for (int i = 0; i < parameters->dim; i++)
-	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	    //printf("\tparameter[%d] = %p\n", i, tp);
-	    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
-
-	    if (ttp)
-	    {
-		printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
-	    }
-	}
-#endif
-    this->loc = loc;
-    this->parameters = parameters;
-    this->origParameters = parameters;
-    this->members = decldefs;
-    this->overnext = NULL;
-    this->overroot = NULL;
-    this->scope = NULL;
-    this->onemember = NULL;
-}
-
-Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
-{
-    //printf("TemplateDeclaration::syntaxCopy()\n");
-    TemplateDeclaration *td;
-    TemplateParameters *p;
-    Array *d;
-
-    p = NULL;
-    if (parameters)
-    {
-	p = new TemplateParameters();
-	p->setDim(parameters->dim);
-	for (int i = 0; i < p->dim; i++)
-	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	    p->data[i] = (void *)tp->syntaxCopy();
-	}
-    }
-    d = Dsymbol::arraySyntaxCopy(members);
-    td = new TemplateDeclaration(loc, ident, p, d);
-    return td;
-}
-
-void TemplateDeclaration::semantic(Scope *sc)
-{
-#if LOG
-    printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars());
-#endif
-    if (scope)
-	return;		// semantic() already run
-
-    if (sc->func)
-    {
-	error("cannot declare template at function scope %s", sc->func->toChars());
-    }
-
-    if (/*global.params.useArrayBounds &&*/ sc->module)
-    {
-	// Generate this function as it may be used
-	// when template is instantiated in other modules
-	sc->module->toModuleArray();
-    }
-
-    if (/*global.params.useAssert &&*/ sc->module)
-    {
-	// Generate this function as it may be used
-	// when template is instantiated in other modules
-	sc->module->toModuleAssert();
-    }
-
-    /* Remember Scope for later instantiations, but make
-     * a copy since attributes can change.
-     */
-    this->scope = new Scope(*sc);
-    this->scope->setNoFree();
-
-    // Set up scope for parameters
-    ScopeDsymbol *paramsym = new ScopeDsymbol();
-    paramsym->parent = sc->parent;
-    Scope *paramscope = sc->push(paramsym);
-    paramscope->parameterSpecialization = 1;
-
-    if (global.params.doDocComments)
-    {
-	origParameters = new TemplateParameters();
-	origParameters->setDim(parameters->dim);
-	for (int i = 0; i < parameters->dim; i++)
-	{
-	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	    origParameters->data[i] = (void *)tp->syntaxCopy();
-	}
-    }
-
-    for (int i = 0; i < parameters->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	tp->declareParameter(paramscope);
-    }
-
-    for (int i = 0; i < parameters->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	tp->semantic(paramscope);
-	if (i + 1 != parameters->dim && tp->isTemplateTupleParameter())
-	    error("template tuple parameter must be last one");
-    }
-
-    paramscope->pop();
-
-    if (members)
-    {
-	Dsymbol *s;
-	if (Dsymbol::oneMembers(members, &s))
-	{
-	    if (s && s->ident && s->ident->equals(ident))
-	    {
-		onemember = s;
-		s->parent = this;
-	    }
-	}
-    }
-
-    /* BUG: should check:
-     *	o no virtual functions or non-static data members of classes
-     */
-}
-
-char *TemplateDeclaration::kind()
-{
-    return (onemember && onemember->isAggregateDeclaration())
-		? onemember->kind()
-		: (char *)"template";
-}
-
-/**********************************
- * Overload existing TemplateDeclaration 'this' with the new one 's'.
- * Return !=0 if successful; i.e. no conflict.
- */
-
-int TemplateDeclaration::overloadInsert(Dsymbol *s)
-{
-    TemplateDeclaration **pf;
-    TemplateDeclaration *f;
-
-#if LOG
-    printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars());
-#endif
-    f = s->isTemplateDeclaration();
-    if (!f)
-	return FALSE;
-    TemplateDeclaration *pthis = this;
-    for (pf = &pthis; *pf; pf = &(*pf)->overnext)
-    {
-#if 0
-	// Conflict if TemplateParameter's match
-	// Will get caught anyway later with TemplateInstance, but
-	// should check it now.
-	TemplateDeclaration *f2 = *pf;
-
-	if (f->parameters->dim != f2->parameters->dim)
-	    goto Lcontinue;
-
-	for (int i = 0; i < f->parameters->dim; i++)
-	{   TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i];
-	    TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i];
-
-	    if (!p1->overloadMatch(p2))
-		goto Lcontinue;
-	}
-
-#if LOG
-	printf("\tfalse: conflict\n");
-#endif
-	return FALSE;
-
-     Lcontinue:
-	;
-#endif
-    }
-
-    f->overroot = this;
-    *pf = f;
-#if LOG
-    printf("\ttrue: no conflict\n");
-#endif
-    return TRUE;
-}
-
-/***************************************
- * Given that ti is an instance of this TemplateDeclaration,
- * deduce the types of the parameters to this, and store
- * those deduced types in dedtypes[].
- * Input:
- *	flag	1: don't do semantic() because of dummy types
- *		2: don't change types in matchArg()
- * Output:
- *	dedtypes	deduced arguments
- * Return match level.
- */
-
-MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti,
-	Objects *dedtypes, int flag)
-{   MATCH m;
-    int dedtypes_dim = dedtypes->dim;
-
-#define LOGM 0
-#if LOGM
-    printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag);
-#endif
-
-#if 0
-    printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim);
-    if (ti->tiargs->dim)
-	printf("ti->tiargs->dim = %d, [0] = %p\n",
-	    ti->tiargs->dim,
-	    ti->tiargs->data[0]);
-#endif
-    dedtypes->zero();
-
-    int parameters_dim = parameters->dim;
-    int variadic = isVariadic() != NULL;
-
-    // If more arguments than parameters, no match
-    if (ti->tiargs->dim > parameters_dim && !variadic)
-    {
-#if LOGM
-	printf(" no match: more arguments than parameters\n");
-#endif
-	return MATCHnomatch;
-    }
-
-    assert(dedtypes_dim == parameters_dim);
-    assert(dedtypes_dim >= ti->tiargs->dim || variadic);
-
-    // Set up scope for parameters
-    assert((size_t)scope > 0x10000);
-    ScopeDsymbol *paramsym = new ScopeDsymbol();
-    paramsym->parent = scope->parent;
-    Scope *paramscope = scope->push(paramsym);
-
-    // Attempt type deduction
-    m = MATCHexact;
-    for (int i = 0; i < dedtypes_dim; i++)
-    {	MATCH m2;
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	Declaration *sparam;
-
-	//printf("\targument [%d]\n", i);
-#if LOGM
-	//printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
-	TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
-	if (ttp)
-	    printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
-#endif
-
-	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
-	//printf("\tm2 = %d\n", m2);
-
-	if (m2 == MATCHnomatch)
-	{
-#if 0
-	    printf("\tmatchArg() for parameter %i failed\n", i);
-#endif
-	    goto Lnomatch;
-	}
-
-	if (m2 < m)
-	    m = m2;
-
-	if (!flag)
-	    sparam->semantic(paramscope);
-	if (!paramscope->insert(sparam))
-	    goto Lnomatch;
-    }
-
-    if (!flag)
-    {
-	// Any parameter left without a type gets the type of its corresponding arg
-	for (int i = 0; i < dedtypes_dim; i++)
-	{
-	    if (!dedtypes->data[i])
-	    {   assert(i < ti->tiargs->dim);
-		dedtypes->data[i] = ti->tiargs->data[i];
-	    }
-	}
-    }
-
-#if LOGM
-    // Print out the results
-    printf("--------------------------\n");
-    printf("template %s\n", toChars());
-    printf("instance %s\n", ti->toChars());
-    if (m)
-    {
-	for (int i = 0; i < dedtypes_dim; i++)
-	{
-	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	    Object *oarg;
-
-	    printf(" [%d]", i);
-
-	    if (i < ti->tiargs->dim)
-		oarg = (Object *)ti->tiargs->data[i];
-	    else
-		oarg = NULL;
-	    tp->print(oarg, (Object *)dedtypes->data[i]);
-	}
-    }
-    else
-	goto Lnomatch;
-#endif
-
-#if LOGM
-    printf(" match = %d\n", m);
-#endif
-    goto Lret;
-
-Lnomatch:
-#if LOGM
-    printf(" no match\n");
-#endif
-    m = MATCHnomatch;
-
-Lret:
-    paramscope->pop();
-#if LOGM
-    printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
-#endif
-    return m;
-}
-
-/********************************************
- * Determine partial specialization order of 'this' vs td2.
- * Returns:
- *	1	this is at least as specialized as td2
- *	0	td2 is more specialized than this
- */
-
-int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2)
-{
-    /* This works by taking the template parameters to this template
-     * declaration and feeding them to td2 as if it were a template
-     * instance.
-     * If it works, then this template is at least as specialized
-     * as td2.
-     */
-
-    TemplateInstance ti(0, ident);	// create dummy template instance
-    Objects dedtypes;
-
-#define LOG_LEASTAS	0
-
-#if LOG_LEASTAS
-    printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars());
-#endif
-
-    // Set type arguments to dummy template instance to be types
-    // generated from the parameters to this template declaration
-    ti.tiargs = new Objects();
-    ti.tiargs->setDim(parameters->dim);
-    for (int i = 0; i < ti.tiargs->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	void *p = tp->dummyArg();
-	if (p)
-	    ti.tiargs->data[i] = p;
-	else
-	    ti.tiargs->setDim(i);
-    }
-
-    // Temporary Array to hold deduced types
-    //dedtypes.setDim(parameters->dim);
-    dedtypes.setDim(td2->parameters->dim);
-
-    // Attempt a type deduction
-    if (td2->matchWithInstance(&ti, &dedtypes, 1))
-    {
-	/* A non-variadic template is more specialized than a
-	 * variadic one.
-	 */
-	if (isVariadic() && !td2->isVariadic())
-	    goto L1;
-
-#if LOG_LEASTAS
-	printf("  matches, so is least as specialized\n");
-#endif
-	return 1;
-    }
-  L1:
-#if LOG_LEASTAS
-    printf("  doesn't match, so is not as specialized\n");
-#endif
-    return 0;
-}
-
-
-/*************************************************
- * Match function arguments against a specific template function.
- * Input:
- *	targsi		Expression/Type initial list of template arguments
- *	fargs		arguments to function
- * Output:
- *	dedargs		Expression/Type deduced template arguments
- * Returns:
- *	match level
- */
-
-MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs,
-	Objects *dedargs)
-{
-    size_t i;
-    size_t nfparams;
-    size_t nfargs;
-    size_t nargsi;		// array size of targsi
-    int fptupindex = -1;
-    int tuple_dim = 0;
-    MATCH match = MATCHexact;
-    FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration();
-    TypeFunction *fdtype;		// type of fd
-    TemplateTupleParameter *tp;
-    Objects dedtypes;	// for T:T*, the dedargs is the T*, dedtypes is the T
-
-#if 0
-    printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
-    for (i = 0; i < fargs->dim; i++)
-    {	Expression *e = (Expression *)fargs->data[i];
-	printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
-    }
-#endif
-
-    assert((size_t)scope > 0x10000);
-
-    dedargs->setDim(parameters->dim);
-    dedargs->zero();
-
-    dedtypes.setDim(parameters->dim);
-    dedtypes.zero();
-
-    // Set up scope for parameters
-    ScopeDsymbol *paramsym = new ScopeDsymbol();
-    paramsym->parent = scope->parent;
-    Scope *paramscope = scope->push(paramsym);
-
-    tp = isVariadic();
-
-    nargsi = 0;
-    if (targsi)
-    {	// Set initial template arguments
-
-	nargsi = targsi->dim;
-	if (nargsi > parameters->dim)
-	{   if (!tp)
-		goto Lnomatch;
-	    dedargs->setDim(nargsi);
-	    dedargs->zero();
-	}
-
-	memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data));
-
-	for (i = 0; i < nargsi; i++)
-	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	    MATCH m;
-	    Declaration *sparam;
-
-	    m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
-	    //printf("\tdeduceType m = %d\n", m);
-	    if (m == MATCHnomatch)
-		goto Lnomatch;
-	    if (m < match)
-		match = m;
-
-	    sparam->semantic(paramscope);
-	    if (!paramscope->insert(sparam))
-		goto Lnomatch;
-	}
-    }
-
-    assert(fd->type->ty == Tfunction);
-    fdtype = (TypeFunction *)fd->type;
-
-    nfparams = Argument::dim(fdtype->parameters); // number of function parameters
-    nfargs = fargs->dim;		// number of function arguments
-
-    /* Check for match of function arguments with variadic template
-     * parameter, such as:
-     *
-     * template Foo(T, A...) { void Foo(T t, A a); }
-     * void main() { Foo(1,2,3); }
-     */
-    tp = isVariadic();
-    if (tp)				// if variadic
-    {
-	if (nfparams == 0)		// if no function parameters
-	{
-	    Tuple *t = new Tuple();
-	    //printf("t = %p\n", t);
-	    dedargs->data[parameters->dim - 1] = (void *)t;
-	    goto L2;
-	}
-	else if (nfargs < nfparams - 1)
-	    goto L1;
-	else
-	{
-	    /* Figure out which of the function parameters matches
-	     * the tuple template parameter. Do this by matching
-	     * type identifiers.
-	     * Set the index of this function parameter to fptupindex.
-	     */
-	    for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
-	    {
-		Argument *fparam = (Argument *)fdtype->parameters->data[fptupindex];
-		if (fparam->type->ty != Tident)
-		    continue;
-		TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
-		if (!tp->ident->equals(tid->ident) || tid->idents.dim)
-		    continue;
-
-		if (fdtype->varargs)	// variadic function doesn't
-		    goto Lnomatch;	// go with variadic template
-
-		/* The types of the function arguments
-		 * now form the tuple argument.
-		 */
-		Tuple *t = new Tuple();
-		dedargs->data[parameters->dim - 1] = (void *)t;
-
-		tuple_dim = nfargs - (nfparams - 1);
-		t->objects.setDim(tuple_dim);
-		for (i = 0; i < tuple_dim; i++)
-		{   Expression *farg = (Expression *)fargs->data[fptupindex + i];
-		    t->objects.data[i] = (void *)farg->type;
-		}
-		goto L2;
-	    }
-	    fptupindex = -1;
-	}
-    }
-
-L1:
-    if (nfparams == nfargs)
-	;
-    else if (nfargs > nfparams)
-    {
-	if (fdtype->varargs == 0)
-	    goto Lnomatch;		// too many args, no match
-	match = MATCHconvert;		// match ... with a conversion
-    }
-
-L2:
-    // Loop through the function parameters
-    for (i = 0; i < nfparams; i++)
-    {
-	/* Skip over function parameters which wound up
-	 * as part of a template tuple parameter.
-	 */
-	if (i == fptupindex)
-	{   if (fptupindex == nfparams - 1)
-		break;
-	    i += tuple_dim - 1;
-	    continue;
-	}
-
-	Argument *fparam = Argument::getNth(fdtype->parameters, i);
-
-	if (i >= nfargs)		// if not enough arguments
-	{
-	    if (fparam->defaultArg)
-	    {	/* Default arguments do not participate in template argument
-		 * deduction.
-		 */
-		goto Lmatch;
-	    }
-	}
-	else
-	{   Expression *farg = (Expression *)fargs->data[i];
-#if 0
-	    printf("\tfarg->type   = %s\n", farg->type->toChars());
-	    printf("\tfparam->type = %s\n", fparam->type->toChars());
-#endif
-
-	    MATCH m;
-	    m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes);
-	    //printf("\tdeduceType m = %d\n", m);
-
-	    /* If no match, see if there's a conversion to a delegate
-	     */
-	    if (!m && fparam->type->toBasetype()->ty == Tdelegate)
-	    {
-		TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype();
-		TypeFunction *tf = (TypeFunction *)td->next;
-
-		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
-		{
-		    m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes);
-		    if (!m && tf->next->toBasetype()->ty == Tvoid)
-			m = MATCHconvert;
-		}
-		//printf("\tm2 = %d\n", m);
-	    }
-
-	    if (m)
-	    {	if (m < match)
-		    match = m;		// pick worst match
-		continue;
-	    }
-	}
-	if (!(fdtype->varargs == 2 && i + 1 == nfparams))
-	    goto Lnomatch;
-
-	/* Check for match with function parameter T...
-	 */
-	Type *t = fparam->type;
-	switch (t->ty)
-	{
-	    // Perhaps we can do better with this, see TypeFunction::callMatch()
-	    case Tsarray:
-	    case Tarray:
-	    case Tclass:
-	    case Tident:
-		goto Lmatch;
-
-	    default:
-		goto Lnomatch;
-	}
-    }
-
-Lmatch:
-
-    /* Fill in any missing arguments with their defaults.
-     */
-    for (i = nargsi; i < dedargs->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	//printf("tp[%d] = %s\n", i, tp->ident->toChars());
-	/* For T:T*, the dedargs is the T*, dedtypes is the T
-	 * But for function templates, we really need them to match
-	 */
-	Object *oarg = (Object *)dedargs->data[i];
-	Object *oded = (Object *)dedtypes.data[i];
-	//printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
-	if (!oarg)
-	{
-	    if (oded)
-	    {
-		if (tp->specialization())
-		{   /* The specialization can work as long as afterwards
-		     * the oded == oarg
-		     */
-		    Declaration *sparam;
-		    dedargs->data[i] = (void *)oded;
-		    MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
-		    //printf("m2 = %d\n", m2);
-		    if (!m2)
-			goto Lnomatch;
-		    if (m2 < match)
-			match = m2;		// pick worst match
-		    if (dedtypes.data[i] != oded)
-			error("specialization not allowed for deduced parameter %s", tp->ident->toChars());
-		}
-	    }
-	    else
-	    {	oded = tp->defaultArg(paramscope);
-		if (!oded)
-		    goto Lnomatch;
-	    }
-	    declareParameter(paramscope, tp, oded);
-	    dedargs->data[i] = (void *)oded;
-	}
-    }
-
-#if 0
-    for (i = 0; i < dedargs->dim; i++)
-    {	Type *t = (Type *)dedargs->data[i];
-	printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars());
-    }
-#endif
-
-    paramscope->pop();
-    //printf("\tmatch %d\n", match);
-    return match;
-
-Lnomatch:
-    paramscope->pop();
-    //printf("\tnomatch\n");
-    return MATCHnomatch;
-}
-
-/**************************************************
- * Declare template parameter tp with value o.
- */
-
-void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o)
-{
-    //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
-
-    Type *targ = isType(o);
-    Expression *ea = isExpression(o);
-    Dsymbol *sa = isDsymbol(o);
-    Tuple *va = isTuple(o);
-
-    Dsymbol *s;
-
-    if (targ)
-    {
-	//printf("type %s\n", targ->toChars());
-	s = new AliasDeclaration(0, tp->ident, targ);
-    }
-    else if (sa)
-    {
-	//printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
-	s = new AliasDeclaration(0, tp->ident, sa);
-    }
-    else if (ea)
-    {
-	// tdtypes.data[i] always matches ea here
-	Initializer *init = new ExpInitializer(loc, ea);
-	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-	assert(tvp);
-
-	VarDeclaration *v = new VarDeclaration(0, tvp->valType, tp->ident, init);
-	v->storage_class = STCconst;
-	s = v;
-    }
-    else if (va)
-    {
-	//printf("\ttuple\n");
-	s = new TupleDeclaration(loc, tp->ident, &va->objects);
-    }
-    else
-    {
-#ifdef DEBUG
-	o->print();
-#endif
-	assert(0);
-    }
-    if (!sc->insert(s))
-	error("declaration %s is already defined", tp->ident->toChars());
-    s->semantic(sc);
-}
-
-/**************************************
- * Determine if TemplateDeclaration is variadic.
- */
-
-TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
-{   size_t dim = parameters->dim;
-    TemplateTupleParameter *tp = NULL;
-
-    if (dim)
-	tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter();
-    return tp;
-}
-
-TemplateTupleParameter *TemplateDeclaration::isVariadic()
-{
-    return ::isVariadic(parameters);
-}
-
-/***********************************
- * We can overload templates.
- */
-
-int TemplateDeclaration::isOverloadable()
-{
-    return 1;
-}
-
-/*************************************************
- * Given function arguments, figure out which template function
- * to expand, and return that function.
- * If no match, give error message and return NULL.
- * Input:
- *	targsi		initial list of template arguments
- *	fargs		arguments to function
- */
-
-FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
-	Objects *targsi, Expressions *fargs)
-{
-    MATCH m_best = MATCHnomatch;
-    TemplateDeclaration *td_ambig = NULL;
-    TemplateDeclaration *td_best = NULL;
-    Objects *tdargs = new Objects();
-    TemplateInstance *ti;
-    FuncDeclaration *fd;
-
-#if 0
-    printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars());
-    printf("    targsi:\n");
-    if (targsi)
-    {	for (int i = 0; i < targsi->dim; i++)
-	{   Object *arg = (Object *)targsi->data[i];
-	    printf("\t%s\n", arg->toChars());
-	}
-    }
-    printf("    fargs:\n");
-    for (int i = 0; i < fargs->dim; i++)
-    {	Expression *arg = (Expression *)fargs->data[i];
-	printf("\t%s %s\n", arg->type->toChars(), arg->toChars());
-	//printf("\tty = %d\n", arg->type->ty);
-    }
-#endif
-
-    for (TemplateDeclaration *td = this; td; td = td->overnext)
-    {
-	if (!td->scope)
-	{
-	    error("forward reference to template %s", td->toChars());
-	    goto Lerror;
-	}
-	if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration())
-	{
-	    error("is not a function template");
-	    goto Lerror;
-	}
-
-	MATCH m;
-	Objects dedargs;
-
-	m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs);
-	//printf("deduceFunctionTemplateMatch = %d\n", m);
-	if (!m)			// if no match
-	    continue;
-
-	if (m < m_best)
-	    goto Ltd_best;
-	if (m > m_best)
-	    goto Ltd;
-
-	{
-	// Disambiguate by picking the most specialized TemplateDeclaration
-	int c1 = td->leastAsSpecialized(td_best);
-	int c2 = td_best->leastAsSpecialized(td);
-	//printf("c1 = %d, c2 = %d\n", c1, c2);
-
-	if (c1 > c2)
-	    goto Ltd;
-	else if (c1 < c2)
-	    goto Ltd_best;
-	else
-	    goto Lambig;
-	}
-
-      Lambig:		// td_best and td are ambiguous
-	td_ambig = td;
-	continue;
-
-      Ltd_best:		// td_best is the best match so far
-	td_ambig = NULL;
-	continue;
-
-      Ltd:		// td is the new best match
-	td_ambig = NULL;
-	assert((size_t)td->scope > 0x10000);
-	td_best = td;
-	m_best = m;
-	tdargs->setDim(dedargs.dim);
-	memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *));
-	continue;
-    }
-    if (!td_best)
-    {
-	error(loc, "does not match any template declaration");
-	goto Lerror;
-    }
-    if (td_ambig)
-    {
-	error(loc, "%s matches more than one function template declaration, %s and %s",
-		toChars(), td_best->toChars(), td_ambig->toChars());
-    }
-
-    /* The best match is td_best with arguments tdargs.
-     * Now instantiate the template.
-     */
-    assert((size_t)td_best->scope > 0x10000);
-    ti = new TemplateInstance(loc, td_best, tdargs);
-    ti->semantic(sc);
-    fd = ti->toAlias()->isFuncDeclaration();
-    if (!fd)
-	goto Lerror;
-    return fd;
-
-  Lerror:
-    {
-	OutBuffer buf;
-	HdrGenState hgs;
-
-	argExpTypesToCBuffer(&buf, fargs, &hgs);
-	error(loc, "cannot deduce template function from argument types (%s)",
-		buf.toChars());
-	return NULL;
-    }
-}
-
-void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-#if 0 // Should handle template functions
-    if (onemember && onemember->isFuncDeclaration())
-	buf->writestring("foo ");
-#endif
-    buf->writestring(kind());
-    buf->writeByte(' ');
-    buf->writestring(ident->toChars());
-    buf->writeByte('(');
-    for (int i = 0; i < parameters->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	if (hgs->ddoc)
-	    tp = (TemplateParameter *)origParameters->data[i];
-	if (i)
-	    buf->writeByte(',');
-	tp->toCBuffer(buf, hgs);
-    }
-    buf->writeByte(')');
-
-    if (hgs->hdrgen)
-    {
-	hgs->tpltMember++;
-	buf->writenl();
-	buf->writebyte('{');
-	buf->writenl();
-	for (int i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->toCBuffer(buf, hgs);
-	}
-	buf->writebyte('}');
-	buf->writenl();
-	hgs->tpltMember--;
-    }
-}
-
-
-char *TemplateDeclaration::toChars()
-{   OutBuffer buf;
-    HdrGenState hgs;
-
-    memset(&hgs, 0, sizeof(hgs));
-    buf.writestring(ident->toChars());
-    buf.writeByte('(');
-    for (int i = 0; i < parameters->dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-	if (i)
-	    buf.writeByte(',');
-	tp->toCBuffer(&buf, &hgs);
-    }
-    buf.writeByte(')');
-    buf.writeByte(0);
-    return (char *)buf.extractData();
-}
-
-/* ======================== Type ============================================ */
-
-/****
- * Given an identifier, figure out which TemplateParameter it is.
- * Return -1 if not found.
- */
-
-int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
-{
-    for (size_t i = 0; i < parameters->dim; i++)
-    {   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	if (tp->ident->equals(id))
-	    return i;
-    }
-    return -1;
-}
-
-int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
-{
-    assert(tparam->ty == Tident);
-    TypeIdentifier *tident = (TypeIdentifier *)tparam;
-    //printf("\ttident = '%s'\n", tident->toChars());
-    if (tident->idents.dim == 0)
-    {
-	return templateIdentifierLookup(tident->ident, parameters);
-    }
-    return -1;
-}
-
-/* These form the heart of template argument deduction.
- * Given 'this' being the type argument to the template instance,
- * it is matched against the template declaration parameter specialization
- * 'tparam' to determine the type to be used for the parameter.
- * Example:
- *	template Foo(T:T*)	// template declaration
- *	Foo!(int*)		// template instantiation
- * Input:
- *	this = int*
- *	tparam = T
- *	parameters = [ T:T* ]	// Array of TemplateParameter's
- * Output:
- *	dedtypes = [ int ]	// Array of Expression/Type's
- */
-
-MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
-	Objects *dedtypes)
-{
-    //printf("Type::deduceType()\n");
-    //printf("\tthis   = %d, ", ty); print();
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
-    if (!tparam)
-	goto Lnomatch;
-
-    if (this == tparam)
-	goto Lexact;
-
-    if (tparam->ty == Tident)
-    {
-	// Determine which parameter tparam is
-	int i = templateParameterLookup(tparam, parameters);
-	if (i == -1)
-	{
-	    if (!sc)
-		goto Lnomatch;
-	    /* BUG: what if tparam is a template instance, that
-	     * has as an argument another Tident?
-	     */
-	    tparam = tparam->semantic(0, sc);
-	    assert(tparam->ty != Tident);
-	    return deduceType(sc, tparam, parameters, dedtypes);
-	}
-
-	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-	// Found the corresponding parameter tp
-	if (!tp->isTemplateTypeParameter())
-	    goto Lnomatch;
-	Type *at = (Type *)dedtypes->data[i];
-	if (!at)
-	{
-	    dedtypes->data[i] = (void *)this;
-	    goto Lexact;
-	}
-	if (equals(at))
-	    goto Lexact;
-	else if (ty == Tclass && at->ty == Tclass)
-	{
-	    return (MATCH) implicitConvTo(at);
-	}
-	else if (ty == Tsarray && at->ty == Tarray &&
-	    nextOf()->equals(at->nextOf()))
-	{
-	    goto Lexact;
-	}
-	else
-	    goto Lnomatch;
-    }
-
-    if (ty != tparam->ty)
-	goto Lnomatch;
-
-    if (nextOf())
-	return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
-
-Lexact:
-    return MATCHexact;
-
-Lnomatch:
-    return MATCHnomatch;
-}
-
-MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
-	Objects *dedtypes)
-{
-#if 0
-    printf("TypeSArray::deduceType()\n");
-    printf("\tthis   = %d, ", ty); print();
-    printf("\ttparam = %d, ", tparam->ty); tparam->print();
-#endif
-
-    // Extra check that array dimensions must match
-    if (tparam)
-    {
-	if (tparam->ty == Tsarray)
-	{
-	    TypeSArray *tp = (TypeSArray *)tparam;
-
-	    if (tp->dim->op == TOKvar &&
-		((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter)
-	    {	int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters);
-		// This code matches code in TypeInstance::deduceType()
-		if (i == -1)
-		    goto Lnomatch;
-		TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-		TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-		if (!tvp)
-		    goto Lnomatch;
-		Expression *e = (Expression *)dedtypes->data[i];
-		if (e)
-		{
-		    if (!dim->equals(e))
-			goto Lnomatch;
-		}
-		else
-		{   Type *vt = tvp->valType->semantic(0, sc);
-		    MATCH m = (MATCH)dim->implicitConvTo(vt);
-		    if (!m)
-			goto Lnomatch;
-		    dedtypes->data[i] = dim;
-		}
-	    }
-	    else if (dim->toInteger() != tp->dim->toInteger())
-		return MATCHnomatch;
-	}
-	else if (tparam->ty == Taarray)
-	{
-	    TypeAArray *tp = (TypeAArray *)tparam;
-	    if (tp->index->ty == Tident)
-	    {	TypeIdentifier *tident = (TypeIdentifier *)tp->index;
-
-		if (tident->idents.dim == 0)
-		{   Identifier *id = tident->ident;
-
-		    for (size_t i = 0; i < parameters->dim; i++)
-		    {
-			TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
-
-			if (tp->ident->equals(id))
-			{   // Found the corresponding template parameter
-			    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-			    if (!tvp || !tvp->valType->isintegral())
-				goto Lnomatch;
-
-			    if (dedtypes->data[i])
-			    {
-				if (!dim->equals((Object *)dedtypes->data[i]))
-				    goto Lnomatch;
-			    }
-			    else
-			    {	dedtypes->data[i] = (void *)dim;
-			    }
-			    return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
-			}
-		    }
-		}
-	    }
-	}
-	else if (tparam->ty == Tarray)
-	{   MATCH m;
-
-	    m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
-	    if (m == MATCHexact)
-		m = MATCHconvert;
-	    return m;
-	}
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-
-  Lnomatch:
-    return MATCHnomatch;
-}
-
-MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-#if 0
-    printf("TypeAArray::deduceType()\n");
-    printf("\tthis   = %d, ", ty); print();
-    printf("\ttparam = %d, ", tparam->ty); tparam->print();
-#endif
-
-    // Extra check that index type must match
-    if (tparam && tparam->ty == Taarray)
-    {
-	TypeAArray *tp = (TypeAArray *)tparam;
-	if (!index->deduceType(sc, tp->index, parameters, dedtypes))
-	{
-	    return MATCHnomatch;
-	}
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    //printf("TypeFunction::deduceType()\n");
-    //printf("\tthis   = %d, ", ty); print();
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
-
-    // Extra check that function characteristics must match
-    if (tparam && tparam->ty == Tfunction)
-    {
-	TypeFunction *tp = (TypeFunction *)tparam;
-	if (varargs != tp->varargs ||
-	    linkage != tp->linkage)
-	    return MATCHnomatch;
-
-	size_t nfargs = Argument::dim(this->parameters);
-	size_t nfparams = Argument::dim(tp->parameters);
-
-	/* See if tuple match
-	 */
-	if (nfparams > 0 && nfargs >= nfparams - 1)
-	{
-	    /* See if 'A' of the template parameter matches 'A'
-	     * of the type of the last function parameter.
-	     */
-	    Argument *fparam = (Argument *)tp->parameters->data[nfparams - 1];
-	    if (fparam->type->ty != Tident)
-		goto L1;
-	    TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
-	    if (tid->idents.dim)
-		goto L1;
-
-	    /* Look through parameters to find tuple matching tid->ident
-	     */
-	    size_t tupi = 0;
-	    for (; 1; tupi++)
-	    {	if (tupi == parameters->dim)
-		    goto L1;
-		TemplateParameter *t = (TemplateParameter *)parameters->data[tupi];
-		TemplateTupleParameter *tup = t->isTemplateTupleParameter();
-		if (tup && tup->ident->equals(tid->ident))
-		    break;
-	    }
-
-	    /* The types of the function arguments [nfparams - 1 .. nfargs]
-	     * now form the tuple argument.
-	     */
-	    int tuple_dim = nfargs - (nfparams - 1);
-
-	    /* See if existing tuple, and whether it matches or not
-	     */
-	    Object *o = (Object *)dedtypes->data[tupi];
-	    if (o)
-	    {	// Existing deduced argument must be a tuple, and must match
-		Tuple *t = isTuple(o);
-		if (!t || t->objects.dim != tuple_dim)
-		    return MATCHnomatch;
-		for (size_t i = 0; i < tuple_dim; i++)
-		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
-		    if (!arg->type->equals((Object *)t->objects.data[i]))
-			return MATCHnomatch;
-		}
-	    }
-	    else
-	    {	// Create new tuple
-		Tuple *t = new Tuple();
-		t->objects.setDim(tuple_dim);
-		for (size_t i = 0; i < tuple_dim; i++)
-		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
-		    t->objects.data[i] = (void *)arg->type;
-		}
-		dedtypes->data[tupi] = (void *)t;
-	    }
-	    nfparams--;	// don't consider the last parameter for type deduction
-	    goto L2;
-	}
-
-    L1:
-	if (nfargs != nfparams)
-	    return MATCHnomatch;
-    L2:
-	for (size_t i = 0; i < nfparams; i++)
-	{
-	    Argument *a = Argument::getNth(this->parameters, i);
-	    Argument *ap = Argument::getNth(tp->parameters, i);
-	    if (a->storageClass != ap->storageClass ||
-		!a->type->deduceType(sc, ap->type, parameters, dedtypes))
-		return MATCHnomatch;
-	}
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    // Extra check
-    if (tparam && tparam->ty == Tident)
-    {
-	TypeIdentifier *tp = (TypeIdentifier *)tparam;
-
-	for (int i = 0; i < idents.dim; i++)
-	{
-	    Identifier *id1 = (Identifier *)idents.data[i];
-	    Identifier *id2 = (Identifier *)tp->idents.data[i];
-
-	    if (!id1->equals(id2))
-		return MATCHnomatch;
-	}
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeInstance::deduceType(Scope *sc,
-	Type *tparam, TemplateParameters *parameters,
-	Objects *dedtypes)
-{
-    //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars());
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
-
-    // Extra check
-    if (tparam && tparam->ty == Tinstance)
-    {
-	TypeInstance *tp = (TypeInstance *)tparam;
-
-	//printf("tempinst->tempdecl = %p\n", tempinst->tempdecl);
-	//printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
-	if (!tp->tempinst->tempdecl)
-	{   //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
-	    if (!tp->tempinst->name->equals(tempinst->name))
-	    {
-		/* Handle case of:
-		 *  template Foo(T : sa!(T), alias sa)
-		 */
-		int i = templateIdentifierLookup(tp->tempinst->name, parameters);
-		if (i == -1)
-		{   /* Didn't find it as a parameter identifier. Try looking
-		     * it up and seeing if is an alias. See Bugzilla 1454
-		     */
-		    Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL);
-		    if (s)
-		    {
-			s = s->toAlias();
-			TemplateDeclaration *td = s->isTemplateDeclaration();
-			if (td && td == tempinst->tempdecl)
-			    goto L2;
-		    }
-		    goto Lnomatch;
-		}
-		TemplateParameter *tpx = (TemplateParameter *)parameters->data[i];
-		// This logic duplicates tpx->matchArg()
-		TemplateAliasParameter *ta = tpx->isTemplateAliasParameter();
-		if (!ta)
-		    goto Lnomatch;
-		Dsymbol *sa = tempinst->tempdecl;
-		if (!sa)
-		    goto Lnomatch;
-		if (ta->specAlias && sa != ta->specAlias)
-		    goto Lnomatch;
-		if (dedtypes->data[i])
-		{   // Must match already deduced symbol
-		    Dsymbol *s = (Dsymbol *)dedtypes->data[i];
-
-		    if (s != sa)
-			goto Lnomatch;
-		}
-		dedtypes->data[i] = sa;
-	    }
-	}
-	else if (tempinst->tempdecl != tp->tempinst->tempdecl)
-	    goto Lnomatch;
-
-      L2:
-	if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim)
-	    goto Lnomatch;
-
-	for (int i = 0; i < tempinst->tiargs->dim; i++)
-	{
-	    //printf("\ttest: tempinst->tiargs[%d]\n", i);
-	    int j;
-	    Object *o1 = (Object *)tempinst->tiargs->data[i];
-	    Object *o2 = (Object *)tp->tempinst->tiargs->data[i];
-
-	    Type *t1 = isType(o1);
-	    Type *t2 = isType(o2);
-
-	    Expression *e1 = isExpression(o1);
-	    Expression *e2 = isExpression(o2);
-
-#if 0
-	    if (t1)	printf("t1 = %s\n", t1->toChars());
-	    if (t2)	printf("t2 = %s\n", t2->toChars());
-	    if (e1)	printf("e1 = %s\n", e1->toChars());
-	    if (e2)	printf("e2 = %s\n", e2->toChars());
-#endif
-
-	    if (t1 && t2)
-	    {
-		if (!t1->deduceType(sc, t2, parameters, dedtypes))
-		    goto Lnomatch;
-	    }
-	    else if (e1 && e2)
-	    {
-		if (!e1->equals(e2))
-		{   if (e2->op == TOKvar)
-		    {
-			/*
-			 * (T:Number!(e2), int e2)
-			 */
-			j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
-			goto L1;
-		    }
-		    goto Lnomatch;
-		}
-	    }
-	    else if (e1 && t2 && t2->ty == Tident)
-	    {
-		j = templateParameterLookup(t2, parameters);
-	    L1:
-		if (j == -1)
-		    goto Lnomatch;
-		TemplateParameter *tp = (TemplateParameter *)parameters->data[j];
-		// BUG: use tp->matchArg() instead of the following
-		TemplateValueParameter *tv = tp->isTemplateValueParameter();
-		if (!tv)
-		    goto Lnomatch;
-		Expression *e = (Expression *)dedtypes->data[j];
-		if (e)
-		{
-		    if (!e1->equals(e))
-			goto Lnomatch;
-		}
-		else
-		{   Type *vt = tv->valType->semantic(0, sc);
-		    MATCH m = (MATCH)e1->implicitConvTo(vt);
-		    if (!m)
-			goto Lnomatch;
-		    dedtypes->data[j] = e1;
-		}
-	    }
-	    // BUG: Need to handle alias and tuple parameters
-	    else
-		goto Lnomatch;
-	}
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-
-Lnomatch:
-    return MATCHnomatch;
-}
-
-MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    //printf("TypeStruct::deduceType()\n");
-    //printf("\tthis->parent   = %s, ", sym->parent->toChars()); print();
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
-
-    /* If this struct is a template struct, and we're matching
-     * it against a template instance, convert the struct type
-     * to a template instance, too, and try again.
-     */
-    TemplateInstance *ti = sym->parent->isTemplateInstance();
-
-    if (tparam && tparam->ty == Tinstance)
-    {
-	if (ti && ti->toAlias() == sym)
-	{
-	    TypeInstance *t = new TypeInstance(0, ti);
-	    return t->deduceType(sc, tparam, parameters, dedtypes);
-	}
-
-	/* Match things like:
-	 *  S!(T).foo
-	 */
-	TypeInstance *tpi = (TypeInstance *)tparam;
-	if (tpi->idents.dim)
-	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
-	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
-	    {
-		Type *tparent = sym->parent->getType();
-		if (tparent)
-		{
-		    /* Slice off the .foo in S!(T).foo
-		     */
-		    tpi->idents.dim--;
-		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
-		    tpi->idents.dim++;
-		    return m;
-		}
-	    }
-	}
-    }
-
-    // Extra check
-    if (tparam && tparam->ty == Tstruct)
-    {
-	TypeStruct *tp = (TypeStruct *)tparam;
-
-	if (sym != tp->sym)
-	    return MATCHnomatch;
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    // Extra check
-    if (tparam && tparam->ty == Tenum)
-    {
-	TypeEnum *tp = (TypeEnum *)tparam;
-
-	if (sym != tp->sym)
-	    return MATCHnomatch;
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    // Extra check
-    if (tparam && tparam->ty == Ttypedef)
-    {
-	TypeTypedef *tp = (TypeTypedef *)tparam;
-
-	if (sym != tp->sym)
-	    return MATCHnomatch;
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
-{
-    //printf("TypeClass::deduceType(this = %s)\n", toChars());
-
-    /* If this class is a template class, and we're matching
-     * it against a template instance, convert the class type
-     * to a template instance, too, and try again.
-     */
-    TemplateInstance *ti = sym->parent->isTemplateInstance();
-
-    if (tparam && tparam->ty == Tinstance)
-    {
-	if (ti && ti->toAlias() == sym)
-	{
-	    TypeInstance *t = new TypeInstance(0, ti);
-	    return t->deduceType(sc, tparam, parameters, dedtypes);
-	}
-
-	/* Match things like:
-	 *  S!(T).foo
-	 */
-	TypeInstance *tpi = (TypeInstance *)tparam;
-	if (tpi->idents.dim)
-	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
-	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
-	    {
-		Type *tparent = sym->parent->getType();
-		if (tparent)
-		{
-		    /* Slice off the .foo in S!(T).foo
-		     */
-		    tpi->idents.dim--;
-		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
-		    tpi->idents.dim++;
-		    return m;
-		}
-	    }
-	}
-    }
-
-    // Extra check
-    if (tparam && tparam->ty == Tclass)
-    {
-	TypeClass *tp = (TypeClass *)tparam;
-
-	//printf("\t%d\n", (MATCH) implicitConvTo(tp));
-	return (MATCH) implicitConvTo(tp);
-    }
-    return Type::deduceType(sc, tparam, parameters, dedtypes);
-}
-
-/* ======================== TemplateParameter =============================== */
-
-TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
-{
-    this->loc = loc;
-    this->ident = ident;
-    this->sparam = NULL;
-}
-
-TemplateTypeParameter  *TemplateParameter::isTemplateTypeParameter()
-{
-    return NULL;
-}
-
-TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
-{
-    return NULL;
-}
-
-TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
-{
-    return NULL;
-}
-
-TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
-{
-    return NULL;
-}
-
-/* ======================== TemplateTypeParameter =========================== */
-
-// type-parameter
-
-TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
-	Type *defaultType)
-    : TemplateParameter(loc, ident)
-{
-    this->ident = ident;
-    this->specType = specType;
-    this->defaultType = defaultType;
-}
-
-TemplateTypeParameter  *TemplateTypeParameter::isTemplateTypeParameter()
-{
-    return this;
-}
-
-TemplateParameter *TemplateTypeParameter::syntaxCopy()
-{
-    TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType);
-    if (tp->specType)
-	tp->specType = specType->syntaxCopy();
-    if (defaultType)
-	tp->defaultType = defaultType->syntaxCopy();
-    return tp;
-}
-
-void TemplateTypeParameter::declareParameter(Scope *sc)
-{
-    //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
-    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
-    sparam = new AliasDeclaration(loc, ident, ti);
-    if (!sc->insert(sparam))
-	error(loc, "parameter '%s' multiply defined", ident->toChars());
-}
-
-void TemplateTypeParameter::semantic(Scope *sc)
-{
-    //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
-    if (specType)
-    {
-	specType = specType->semantic(loc, sc);
-    }
-#if 0 // Don't do semantic() until instantiation
-    if (defaultType)
-    {
-	defaultType = defaultType->semantic(loc, sc);
-    }
-#endif
-}
-
-/****************************************
- * Determine if two TemplateParameters are the same
- * as far as TemplateDeclaration overloading goes.
- * Returns:
- *	1	match
- *	0	no match
- */
-
-int TemplateTypeParameter::overloadMatch(TemplateParameter *tp)
-{
-    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
-
-    if (ttp)
-    {
-	if (specType != ttp->specType)
-	    goto Lnomatch;
-
-	if (specType && !specType->equals(ttp->specType))
-	    goto Lnomatch;
-
-	return 1;			// match
-    }
-
-Lnomatch:
-    return 0;
-}
-
-/*******************************************
- * Match to a particular TemplateParameter.
- * Input:
- *	i		i'th argument
- *	tiargs[]	actual arguments to template instance
- *	parameters[]	template parameters
- *	dedtypes[]	deduced arguments to template instance
- *	*psparam	set to symbol declared and initialized to dedtypes[i]
- */
-
-MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs,
-	int i, TemplateParameters *parameters, Objects *dedtypes,
-	Declaration **psparam)
-{
-    //printf("TemplateTypeParameter::matchArg()\n");
-    Type *t;
-    Object *oarg;
-    MATCH m = MATCHexact;
-    Type *ta;
-
-    if (i < tiargs->dim)
-	oarg = (Object *)tiargs->data[i];
-    else
-    {	// Get default argument instead
-	oarg = defaultArg(sc);
-	if (!oarg)
-	{   assert(i < dedtypes->dim);
-	    // It might have already been deduced
-	    oarg = (Object *)dedtypes->data[i];
-	    if (!oarg)
-		goto Lnomatch;
-	}
-    }
-
-    ta = isType(oarg);
-    if (!ta)
-	goto Lnomatch;
-    //printf("ta is %s\n", ta->toChars());
-
-    t = (Type *)dedtypes->data[i];
-
-    if (specType)
-    {
-	//printf("\tcalling deduceType(), specType is %s\n", specType->toChars());
-	MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes);
-	if (m2 == MATCHnomatch)
-	{   //printf("\tfailed deduceType\n");
-	    goto Lnomatch;
-	}
-
-	if (m2 < m)
-	    m = m2;
-	t = (Type *)dedtypes->data[i];
-    }
-    else
-    {
-	m = MATCHconvert;
-	if (t)
-	{   // Must match already deduced type
-
-	    m = MATCHexact;
-	    if (!t->equals(ta))
-		goto Lnomatch;
-	}
-    }
-
-    if (!t)
-    {
-	dedtypes->data[i] = ta;
-	t = ta;
-    }
-    *psparam = new AliasDeclaration(loc, ident, t);
-    //printf("\tm = %d\n", m);
-    return m;
-
-Lnomatch:
-    *psparam = NULL;
-    //printf("\tm = %d\n", MATCHnomatch);
-    return MATCHnomatch;
-}
-
-
-void TemplateTypeParameter::print(Object *oarg, Object *oded)
-{
-    printf(" %s\n", ident->toChars());
-
-    Type *t  = isType(oarg);
-    Type *ta = isType(oded);
-
-    assert(ta);
-
-    if (specType)
-	printf("\tSpecialization: %s\n", specType->toChars());
-    if (defaultType)
-	printf("\tDefault:        %s\n", defaultType->toChars());
-    printf("\tArgument:       %s\n", t ? t->toChars() : "NULL");
-    printf("\tDeduced Type:   %s\n", ta->toChars());
-}
-
-
-void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring(ident->toChars());
-    if (specType)
-    {
-	buf->writestring(" : ");
-	specType->toCBuffer(buf, NULL, hgs);
-    }
-    if (defaultType)
-    {
-	buf->writestring(" = ");
-	defaultType->toCBuffer(buf, NULL, hgs);
-    }
-}
-
-
-void *TemplateTypeParameter::dummyArg()
-{   Type *t;
-
-    if (specType)
-	t = specType;
-    else
-    {   // Use this for alias-parameter's too (?)
-	t = new TypeIdentifier(loc, ident);
-    }
-    return (void *)t;
-}
-
-
-Object *TemplateTypeParameter::specialization()
-{
-    return specType;
-}
-
-
-Object *TemplateTypeParameter::defaultArg(Scope *sc)
-{
-    Type *t;
-
-    t = defaultType;
-    if (t)
-    {
-	t = t->syntaxCopy();
-	t = t->semantic(loc, sc);
-    }
-    return t;
-}
-
-/* ======================== TemplateAliasParameter ========================== */
-
-// alias-parameter
-
-Dsymbol *TemplateAliasParameter::sdummy = NULL;
-
-TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias)
-    : TemplateParameter(loc, ident)
-{
-    this->ident = ident;
-    this->specAliasT = specAliasT;
-    this->defaultAlias = defaultAlias;
-
-    this->specAlias = NULL;
-}
-
-TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
-{
-    return this;
-}
-
-TemplateParameter *TemplateAliasParameter::syntaxCopy()
-{
-    TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias);
-    if (tp->specAliasT)
-	tp->specAliasT = specAliasT->syntaxCopy();
-    if (defaultAlias)
-	tp->defaultAlias = defaultAlias->syntaxCopy();
-    return tp;
-}
-
-void TemplateAliasParameter::declareParameter(Scope *sc)
-{
-    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
-    sparam = new AliasDeclaration(loc, ident, ti);
-    if (!sc->insert(sparam))
-	error(loc, "parameter '%s' multiply defined", ident->toChars());
-}
-
-void TemplateAliasParameter::semantic(Scope *sc)
-{
-    if (specAliasT)
-    {
-	specAlias = specAliasT->toDsymbol(sc);
-	if (!specAlias)
-	    error("%s is not a symbol", specAliasT->toChars());
-    }
-#if 0 // Don't do semantic() until instantiation
-    if (defaultAlias)
-	defaultAlias = defaultAlias->semantic(loc, sc);
-#endif
-}
-
-int TemplateAliasParameter::overloadMatch(TemplateParameter *tp)
-{
-    TemplateAliasParameter *tap = tp->isTemplateAliasParameter();
-
-    if (tap)
-    {
-	if (specAlias != tap->specAlias)
-	    goto Lnomatch;
-
-	return 1;			// match
-    }
-
-Lnomatch:
-    return 0;
-}
-
-MATCH TemplateAliasParameter::matchArg(Scope *sc,
-	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
-	Declaration **psparam)
-{
-    Dsymbol *sa;
-    Object *oarg;
-    Expression *ea;
-
-    //printf("TemplateAliasParameter::matchArg()\n");
-
-    if (i < tiargs->dim)
-	oarg = (Object *)tiargs->data[i];
-    else
-    {	// Get default argument instead
-	oarg = defaultArg(sc);
-	if (!oarg)
-	{   assert(i < dedtypes->dim);
-	    // It might have already been deduced
-	    oarg = (Object *)dedtypes->data[i];
-	    if (!oarg)
-		goto Lnomatch;
-	}
-    }
-
-    sa = getDsymbol(oarg);
-    if (!sa)
-	goto Lnomatch;
-
-    if (specAlias)
-    {
-	if (!sa || sa == sdummy)
-	    goto Lnomatch;
-	if (sa != specAlias)
-	    goto Lnomatch;
-    }
-    else if (dedtypes->data[i])
-    {   // Must match already deduced symbol
-	Dsymbol *s = (Dsymbol *)dedtypes->data[i];
-
-	if (!sa || s != sa)
-	    goto Lnomatch;
-    }
-    dedtypes->data[i] = sa;
-
-    *psparam = new AliasDeclaration(loc, ident, sa);
-    return MATCHexact;
-
-Lnomatch:
-    *psparam = NULL;
-    return MATCHnomatch;
-}
-
-
-void TemplateAliasParameter::print(Object *oarg, Object *oded)
-{
-    printf(" %s\n", ident->toChars());
-
-    Dsymbol *sa = isDsymbol(oded);
-    assert(sa);
-
-    printf("\tArgument alias: %s\n", sa->toChars());
-}
-
-void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("alias ");
-    buf->writestring(ident->toChars());
-    if (specAliasT)
-    {
-	buf->writestring(" : ");
-	specAliasT->toCBuffer(buf, NULL, hgs);
-    }
-    if (defaultAlias)
-    {
-	buf->writestring(" = ");
-	defaultAlias->toCBuffer(buf, NULL, hgs);
-    }
-}
-
-
-void *TemplateAliasParameter::dummyArg()
-{   Dsymbol *s;
-
-    s = specAlias;
-    if (!s)
-    {
-	if (!sdummy)
-	    sdummy = new Dsymbol();
-	s = sdummy;
-    }
-    return (void*)s;
-}
-
-
-Object *TemplateAliasParameter::specialization()
-{
-    return specAliasT;
-}
-
-
-Object *TemplateAliasParameter::defaultArg(Scope *sc)
-{
-    Dsymbol *s = NULL;
-
-    if (defaultAlias)
-    {
-	s = defaultAlias->toDsymbol(sc);
-	if (!s)
-	    error("%s is not a symbol", defaultAlias->toChars());
-    }
-    return s;
-}
-
-/* ======================== TemplateValueParameter ========================== */
-
-// value-parameter
-
-Expression *TemplateValueParameter::edummy = NULL;
-
-TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
-	Expression *specValue, Expression *defaultValue)
-    : TemplateParameter(loc, ident)
-{
-    this->ident = ident;
-    this->valType = valType;
-    this->specValue = specValue;
-    this->defaultValue = defaultValue;
-}
-
-TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
-{
-    return this;
-}
-
-TemplateParameter *TemplateValueParameter::syntaxCopy()
-{
-    TemplateValueParameter *tp =
-	new TemplateValueParameter(loc, ident, valType, specValue, defaultValue);
-    tp->valType = valType->syntaxCopy();
-    if (specValue)
-	tp->specValue = specValue->syntaxCopy();
-    if (defaultValue)
-	tp->defaultValue = defaultValue->syntaxCopy();
-    return tp;
-}
-
-void TemplateValueParameter::declareParameter(Scope *sc)
-{
-    VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
-    v->storage_class = STCtemplateparameter;
-    if (!sc->insert(v))
-	error(loc, "parameter '%s' multiply defined", ident->toChars());
-    sparam = v;
-}
-
-void TemplateValueParameter::semantic(Scope *sc)
-{
-    sparam->semantic(sc);
-    valType = valType->semantic(loc, sc);
-    if (!(valType->isintegral() || valType->isfloating() || valType->isString()) &&
-	valType->ty != Tident)
-	error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars());
-
-    if (specValue)
-    {   Expression *e = specValue;
-
-	e = e->semantic(sc);
-	e = e->implicitCastTo(sc, valType);
-	e = e->optimize(WANTvalue | WANTinterpret);
-	if (e->op == TOKint64 || e->op == TOKfloat64 ||
-	    e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring)
-	    specValue = e;
-	//e->toInteger();
-    }
-
-#if 0	// defer semantic analysis to arg match
-    if (defaultValue)
-    {   Expression *e = defaultValue;
-
-	e = e->semantic(sc);
-	e = e->implicitCastTo(sc, valType);
-	e = e->optimize(WANTvalue | WANTinterpret);
-	if (e->op == TOKint64)
-	    defaultValue = e;
-	//e->toInteger();
-    }
-#endif
-}
-
-int TemplateValueParameter::overloadMatch(TemplateParameter *tp)
-{
-    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-
-    if (tvp)
-    {
-	if (valType != tvp->valType)
-	    goto Lnomatch;
-
-	if (valType && !valType->equals(tvp->valType))
-	    goto Lnomatch;
-
-	if (specValue != tvp->specValue)
-	    goto Lnomatch;
-
-	return 1;			// match
-    }
-
-Lnomatch:
-    return 0;
-}
-
-
-MATCH TemplateValueParameter::matchArg(Scope *sc,
-	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
-	Declaration **psparam)
-{
-    //printf("TemplateValueParameter::matchArg()\n");
-
-    Initializer *init;
-    Declaration *sparam;
-    MATCH m = MATCHexact;
-    Expression *ei;
-    Object *oarg;
-
-    if (i < tiargs->dim)
-	oarg = (Object *)tiargs->data[i];
-    else
-    {	// Get default argument instead
-	oarg = defaultArg(sc);
-	if (!oarg)
-	{   assert(i < dedtypes->dim);
-	    // It might have already been deduced
-	    oarg = (Object *)dedtypes->data[i];
-	    if (!oarg)
-		goto Lnomatch;
-	}
-    }
-
-    ei = isExpression(oarg);
-    Type *vt;
-
-    if (!ei && oarg)
-	goto Lnomatch;
-
-    if (specValue)
-    {
-	if (!ei || ei == edummy)
-	    goto Lnomatch;
-
-	Expression *e = specValue;
-
-	e = e->semantic(sc);
-	e = e->implicitCastTo(sc, valType);
-	e = e->optimize(WANTvalue | WANTinterpret);
-
-	ei = ei->syntaxCopy();
-	ei = ei->semantic(sc);
-	ei = ei->optimize(WANTvalue | WANTinterpret);
-	//printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
-	//printf("e : %s, %s\n", e->toChars(), e->type->toChars());
-	if (!ei->equals(e))
-	    goto Lnomatch;
-    }
-    else if (dedtypes->data[i])
-    {   // Must match already deduced value
-	Expression *e = (Expression *)dedtypes->data[i];
-
-	if (!ei || !ei->equals(e))
-	    goto Lnomatch;
-    }
-Lmatch:
-    //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty);
-    vt = valType->semantic(0, sc);
-    //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
-    if (ei->type)
-    {
-	m = (MATCH)ei->implicitConvTo(vt);
-	//printf("m: %d\n", m);
-	if (!m)
-	    goto Lnomatch;
-    }
-    dedtypes->data[i] = ei;
-
-    init = new ExpInitializer(loc, ei);
-    sparam = new VarDeclaration(loc, vt, ident, init);
-    sparam->storage_class = STCconst;
-    *psparam = sparam;
-    return m;
-
-Lnomatch:
-    //printf("\tno match\n");
-    *psparam = NULL;
-    return MATCHnomatch;
-}
-
-
-void TemplateValueParameter::print(Object *oarg, Object *oded)
-{
-    printf(" %s\n", ident->toChars());
-
-    Expression *ea = isExpression(oded);
-
-    if (specValue)
-	printf("\tSpecialization: %s\n", specValue->toChars());
-    printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL");
-}
-
-
-void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    valType->toCBuffer(buf, ident, hgs);
-    if (specValue)
-    {
-	buf->writestring(" : ");
-	specValue->toCBuffer(buf, hgs);
-    }
-    if (defaultValue)
-    {
-	buf->writestring(" = ");
-	defaultValue->toCBuffer(buf, hgs);
-    }
-}
-
-
-void *TemplateValueParameter::dummyArg()
-{   Expression *e;
-
-    e = specValue;
-    if (!e)
-    {
-	// Create a dummy value
-	if (!edummy)
-	    edummy = valType->defaultInit();
-	e = edummy;
-    }
-    return (void *)e;
-}
-
-
-Object *TemplateValueParameter::specialization()
-{
-    return specValue;
-}
-
-
-Object *TemplateValueParameter::defaultArg(Scope *sc)
-{
-    Expression *e;
-
-    e = defaultValue;
-    if (e)
-    {
-	e = e->syntaxCopy();
-	e = e->semantic(sc);
-    }
-    return e;
-}
-
-/* ======================== TemplateTupleParameter ========================== */
-
-// variadic-parameter
-
-TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
-    : TemplateParameter(loc, ident)
-{
-    this->ident = ident;
-}
-
-TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
-{
-    return this;
-}
-
-TemplateParameter *TemplateTupleParameter::syntaxCopy()
-{
-    TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident);
-    return tp;
-}
-
-void TemplateTupleParameter::declareParameter(Scope *sc)
-{
-    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
-    sparam = new AliasDeclaration(loc, ident, ti);
-    if (!sc->insert(sparam))
-	error(loc, "parameter '%s' multiply defined", ident->toChars());
-}
-
-void TemplateTupleParameter::semantic(Scope *sc)
-{
-}
-
-int TemplateTupleParameter::overloadMatch(TemplateParameter *tp)
-{
-    TemplateTupleParameter *tvp = tp->isTemplateTupleParameter();
-
-    if (tvp)
-    {
-	return 1;			// match
-    }
-
-Lnomatch:
-    return 0;
-}
-
-MATCH TemplateTupleParameter::matchArg(Scope *sc,
-	Objects *tiargs, int i, TemplateParameters *parameters,
-	Objects *dedtypes,
-	Declaration **psparam)
-{
-    //printf("TemplateTupleParameter::matchArg()\n");
-
-    /* The rest of the actual arguments (tiargs[]) form the match
-     * for the variadic parameter.
-     */
-    assert(i + 1 == dedtypes->dim);	// must be the last one
-    Tuple *ovar;
-    if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i]))
-	ovar = isTuple((Object *)tiargs->data[i]);
-    else
-    {
-	ovar = new Tuple();
-	//printf("ovar = %p\n", ovar);
-	if (i < tiargs->dim)
-	{
-	    //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim);
-	    ovar->objects.setDim(tiargs->dim - i);
-	    for (size_t j = 0; j < ovar->objects.dim; j++)
-		ovar->objects.data[j] = tiargs->data[i + j];
-	}
-    }
-    *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
-    dedtypes->data[i] = (void *)ovar;
-    return MATCHexact;
-}
-
-
-void TemplateTupleParameter::print(Object *oarg, Object *oded)
-{
-    printf(" %s... [", ident->toChars());
-    Tuple *v = isTuple(oded);
-    assert(v);
-
-    //printf("|%d| ", v->objects.dim);
-    for (int i = 0; i < v->objects.dim; i++)
-    {
-	if (i)
-	    printf(", ");
-
-	Object *o = (Object *)v->objects.data[i];
-
-	Dsymbol *sa = isDsymbol(o);
-	if (sa)
-	    printf("alias: %s", sa->toChars());
-
-	Type *ta = isType(o);
-	if (ta)
-	    printf("type: %s", ta->toChars());
-
-	Expression *ea = isExpression(o);
-	if (ea)
-	    printf("exp: %s", ea->toChars());
-
-	assert(!isTuple(o));		// no nested Tuple arguments
-    }
-
-    printf("]\n");
-}
-
-void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring(ident->toChars());
-    buf->writestring("...");
-}
-
-
-void *TemplateTupleParameter::dummyArg()
-{
-    return NULL;
-}
-
-
-Object *TemplateTupleParameter::specialization()
-{
-    return NULL;
-}
-
-
-Object *TemplateTupleParameter::defaultArg(Scope *sc)
-{
-    return NULL;
-}
-
-/* ======================== TemplateInstance ================================ */
-
-TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
-    : ScopeDsymbol(NULL)
-{
-#if LOG
-    printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null");
-#endif
-    this->loc = loc;
-    this->name = ident;
-    this->tiargs = NULL;
-    this->tempdecl = NULL;
-    this->inst = NULL;
-    this->argsym = NULL;
-    this->aliasdecl = NULL;
-    this->semanticdone = 0;
-    this->withsym = NULL;
-    this->nest = 0;
-    this->havetempdecl = 0;
-    this->isnested = NULL;
-    this->errors = 0;
-}
-
-
-TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
-    : ScopeDsymbol(NULL)
-{
-#if LOG
-    printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars());
-#endif
-    this->loc = loc;
-    this->name = td->ident;
-    this->tiargs = tiargs;
-    this->tempdecl = td;
-    this->inst = NULL;
-    this->argsym = NULL;
-    this->aliasdecl = NULL;
-    this->semanticdone = 0;
-    this->withsym = NULL;
-    this->nest = 0;
-    this->havetempdecl = 1;
-    this->isnested = NULL;
-    this->errors = 0;
-
-    assert((size_t)tempdecl->scope > 0x10000);
-}
-
-
-Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
-{
-    Objects *a = NULL;
-    if (objs)
-    {	a = new Objects();
-	a->setDim(objs->dim);
-	for (size_t i = 0; i < objs->dim; i++)
-	{
-	    Type *ta = isType((Object *)objs->data[i]);
-	    if (ta)
-		a->data[i] = ta->syntaxCopy();
-	    else
-	    {
-		Expression *ea = isExpression((Object *)objs->data[i]);
-		assert(ea);
-		a->data[i] = ea->syntaxCopy();
-	    }
-	}
-    }
-    return a;
-}
-
-Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
-{
-    TemplateInstance *ti;
-    int i;
-
-    if (s)
-	ti = (TemplateInstance *)s;
-    else
-	ti = new TemplateInstance(loc, name);
-
-    ti->tiargs = arraySyntaxCopy(tiargs);
-
-    ScopeDsymbol::syntaxCopy(ti);
-    return ti;
-}
-
-
-void TemplateInstance::semantic(Scope *sc)
-{
-    if (global.errors)
-    {
-	if (!global.gag)
-	{
-	    /* Trying to soldier on rarely generates useful messages
-	     * at this point.
-	     */
-	    fatal();
-	}
-	return;
-    }
-#if LOG
-    printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
-#endif
-    if (inst)		// if semantic() was already run
-    {
-#if LOG
-	printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst);
-#endif
-	return;
-    }
-
-    if (semanticdone != 0)
-    {
-	error(loc, "recursive template expansion");
-//	inst = this;
-	return;
-    }
-    semanticdone = 1;
-
-#if LOG
-    printf("\tdo semantic\n");
-#endif
-    if (havetempdecl)
-    {
-	assert((size_t)tempdecl->scope > 0x10000);
-	// Deduce tdtypes
-	tdtypes.setDim(tempdecl->parameters->dim);
-	if (!tempdecl->matchWithInstance(this, &tdtypes, 0))
-	{
-	    error("incompatible arguments for template instantiation");
-	    inst = this;
-	    return;
-	}
-    }
-    else
-    {
-	// Run semantic on each argument, place results in tiargs[]
-	semanticTiargs(sc);
-
-	tempdecl = findTemplateDeclaration(sc);
-	if (tempdecl)
-	    tempdecl = findBestMatch(sc);
-	if (!tempdecl || global.errors)
-	{   inst = this;
-	    //printf("error return %p, %d\n", tempdecl, global.errors);
-	    return;		// error recovery
-	}
-    }
-
-    isNested(tiargs);
-
-    /* See if there is an existing TemplateInstantiation that already
-     * implements the typeargs. If so, just refer to that one instead.
-     */
-
-    for (size_t i = 0; i < tempdecl->instances.dim; i++)
-    {
-	TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i];
-#if LOG
-	printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars());
-#endif
-	assert(tdtypes.dim == ti->tdtypes.dim);
-
-	// Nesting must match
-	if (isnested != ti->isnested)
-	    continue;
-#if 0
-	if (isnested && sc->parent != ti->parent)
-	    continue;
-#endif
-	for (size_t j = 0; j < tdtypes.dim; j++)
-	{   Object *o1 = (Object *)tdtypes.data[j];
-	    Object *o2 = (Object *)ti->tdtypes.data[j];
-	    if (!match(o1, o2, tempdecl, sc))
-		goto L1;
-	}
-
-	// It's a match
-	inst = ti;
-	parent = ti->parent;
-#if LOG
-	printf("\tit's a match with instance %p\n", inst);
-#endif
-	return;
-
-     L1:
-	;
-    }
-
-    /* So, we need to implement 'this' instance.
-     */
-#if LOG
-    printf("\timplement template instance '%s'\n", toChars());
-#endif
-    unsigned errorsave = global.errors;
-    inst = this;
-    int tempdecl_instance_idx = tempdecl->instances.dim;
-    tempdecl->instances.push(this);
-    parent = tempdecl->parent;
-    //printf("parent = '%s'\n", parent->kind());
-
-    ident = genIdent();		// need an identifier for name mangling purposes.
-
-#if 1
-    if (isnested)
-	parent = isnested;
-#endif
-    //printf("parent = '%s'\n", parent->kind());
-
-    // Add 'this' to the enclosing scope's members[] so the semantic routines
-    // will get called on the instance members
-#if 1
-    int dosemantic3 = 0;
-    {	Array *a;
-	int i;
-
-	if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin())
-	{
-	    //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
-	    a = sc->scopesym->members;
-	}
-	else
-	{   Module *m = sc->module->importedFrom;
-	    //printf("\t2: adding to module %s\n", m->toChars());
-	    a = m->members;
-	    if (m->semanticdone >= 3)
-		dosemantic3 = 1;
-	}
-	for (int i = 0; 1; i++)
-	{
-	    if (i == a->dim)
-	    {
-		a->push(this);
-		break;
-	    }
-	    if (this == (Dsymbol *)a->data[i])	// if already in Array
-		break;
-	}
-    }
-#endif
-
-    // Copy the syntax trees from the TemplateDeclaration
-    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
-
-    // Create our own scope for the template parameters
-    Scope *scope = tempdecl->scope;
-    if (!scope)
-    {
-	error("forward reference to template declaration %s\n", tempdecl->toChars());
-	return;
-    }
-
-#if LOG
-    printf("\tcreate scope for template parameters '%s'\n", toChars());
-#endif
-    argsym = new ScopeDsymbol();
-    argsym->parent = scope->parent;
-    scope = scope->push(argsym);
-
-    // Declare each template parameter as an alias for the argument type
-    declareParameters(scope);
-
-    // Add members of template instance to template instance symbol table
-//    parent = scope->scopesym;
-    symtab = new DsymbolTable();
-    int memnum = 0;
-    for (int i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-#if LOG
-	printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum);
-#endif
-	memnum |= s->addMember(scope, this, memnum);
-    }
-#if LOG
-    printf("adding members done\n");
-#endif
-
-    /* See if there is only one member of template instance, and that
-     * member has the same name as the template instance.
-     * If so, this template instance becomes an alias for that member.
-     */
-    //printf("members->dim = %d\n", members->dim);
-    if (members->dim)
-    {
-	Dsymbol *s;
-	if (Dsymbol::oneMembers(members, &s) && s)
-	{
-	    //printf("s->kind = '%s'\n", s->kind());
-	    //s->print();
-	    //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars());
-	    if (s->ident && s->ident->equals(tempdecl->ident))
-	    {
-		//printf("setting aliasdecl\n");
-		aliasdecl = new AliasDeclaration(loc, s->ident, s);
-	    }
-	}
-    }
-
-    // Do semantic() analysis on template instance members
-#if LOG
-    printf("\tdo semantic() on template instance members '%s'\n", toChars());
-#endif
-    Scope *sc2;
-    sc2 = scope->push(this);
-    //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars());
-    sc2->parent = /*isnested ? sc->parent :*/ this;
-
-#if !IN_LLVM    
-#if _WIN32
-  __try
-  {
-#endif
-#endif
-    for (int i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	//printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
-	//printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars());
-//	if (isnested)
-//	    s->parent = sc->parent;
-	//printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
-	s->semantic(sc2);
-	//printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
-	sc2->module->runDeferredSemantic();
-    }
-#if !IN_LLVM    
-#if _WIN32
-  }
-  __except (__ehfilter(GetExceptionInformation()))
-  {
-    global.gag = 0;			// ensure error message gets printed
-    error("recursive expansion");
-    fatal();
-  }
-#endif
-#endif
-
-    /* If any of the instantiation members didn't get semantic() run
-     * on them due to forward references, we cannot run semantic2()
-     * or semantic3() yet.
-     */
-    for (size_t i = 0; i < Module::deferred.dim; i++)
-    {	Dsymbol *sd = (Dsymbol *)Module::deferred.data[i];
-
-	if (sd->parent == this)
-	    goto Laftersemantic;
-    }
-
-    /* The problem is when to parse the initializer for a variable.
-     * Perhaps VarDeclaration::semantic() should do it like it does
-     * for initializers inside a function.
-     */
-//    if (sc->parent->isFuncDeclaration())
-
-	/* BUG 782: this has problems if the classes this depends on
-	 * are forward referenced. Find a way to defer semantic()
-	 * on this template.
-	 */
-	semantic2(sc2);
-
-    if (sc->func || dosemantic3)
-    {
-	semantic3(sc2);
-    }
-
-  Laftersemantic:
-    sc2->pop();
-
-    scope->pop();
-
-    // Give additional context info if error occurred during instantiation
-    if (global.errors != errorsave)
-    {
-	error("error instantiating");
-	errors = 1;
-	if (global.gag)
-	    tempdecl->instances.remove(tempdecl_instance_idx);
-    }
-
-#if LOG
-    printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
-#endif
-}
-
-
-void TemplateInstance::semanticTiargs(Scope *sc)
-{
-    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
-    semanticTiargs(loc, sc, tiargs);
-}
-
-void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs)
-{
-    // Run semantic on each argument, place results in tiargs[]
-    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
-    if (!tiargs)
-	return;
-    for (size_t j = 0; j < tiargs->dim; j++)
-    {
-	Object *o = (Object *)tiargs->data[j];
-	Type *ta = isType(o);
-	Expression *ea = isExpression(o);
-	Dsymbol *sa = isDsymbol(o);
-
-	//printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
-	if (ta)
-	{
-	    //printf("type %s\n", ta->toChars());
-	    // It might really be an Expression or an Alias
-	    ta->resolve(loc, sc, &ea, &ta, &sa);
-	    if (ea)
-	    {
-		ea = ea->semantic(sc);
-		ea = ea->optimize(WANTvalue | WANTinterpret);
-		tiargs->data[j] = ea;
-	    }
-	    else if (sa)
-	    {	tiargs->data[j] = sa;
-		TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
-		if (d)
-		{
-		    size_t dim = d->objects->dim;
-		    tiargs->remove(j);
-		    tiargs->insert(j, d->objects);
-		    j--;
-		}
-	    }
-	    else if (ta)
-	    {
-		if (ta->ty == Ttuple)
-		{   // Expand tuple
-		    TypeTuple *tt = (TypeTuple *)ta;
-		    size_t dim = tt->arguments->dim;
-		    tiargs->remove(j);
-		    if (dim)
-		    {	tiargs->reserve(dim);
-			for (size_t i = 0; i < dim; i++)
-			{   Argument *arg = (Argument *)tt->arguments->data[i];
-			    tiargs->insert(j + i, arg->type);
-			}
-		    }
-		    j--;
-		}
-		else
-		    tiargs->data[j] = ta;
-	    }
-	    else
-	    {
-		assert(global.errors);
-		tiargs->data[j] = Type::terror;
-	    }
-	}
-	else if (ea)
-	{
-	    if (!ea)
-	    {	assert(global.errors);
-		ea = new IntegerExp(0);
-	    }
-	    assert(ea);
-	    ea = ea->semantic(sc);
-	    ea = ea->optimize(WANTvalue | WANTinterpret);
-	    tiargs->data[j] = ea;
-	    if (ea->op == TOKtype)
-		tiargs->data[j] = ea->type;
-	}
-	else if (sa)
-	{
-	}
-	else
-	{
-	    assert(0);
-	}
-	//printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]);
-    }
-#if 0
-    printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this);
-    for (size_t j = 0; j < tiargs->dim; j++)
-    {
-	Object *o = (Object *)tiargs->data[j];
-	Type *ta = isType(o);
-	Expression *ea = isExpression(o);
-	Dsymbol *sa = isDsymbol(o);
-	Tuple *va = isTuple(o);
-
-	printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
-    }
-#endif
-}
-
-/**********************************************
- * Find template declaration corresponding to template instance.
- */
-
-TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc)
-{
-    //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars());
-    if (!tempdecl)
-    {
-	/* Given:
-	 *    foo!( ... )
-	 * figure out which TemplateDeclaration foo refers to.
-	 */
-	Dsymbol *s;
-	Dsymbol *scopesym;
-	Identifier *id;
-	int i;
-
-	id = name;
-	s = sc->search(loc, id, &scopesym);
-	if (!s)
-	{   error("identifier '%s' is not defined", id->toChars());
-	    return NULL;
-	}
-#if LOG
-	printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind());
-	if (s->parent)
-	    printf("s->parent = '%s'\n", s->parent->toChars());
-#endif
-	withsym = scopesym->isWithScopeSymbol();
-
-	/* We might have found an alias within a template when
-	 * we really want the template.
-	 */
-	TemplateInstance *ti;
-	if (s->parent &&
-	    (ti = s->parent->isTemplateInstance()) != NULL)
-	{
-	    if (
-		(ti->name == id ||
-		 ti->toAlias()->ident == id)
-		&&
-		ti->tempdecl)
-	    {
-		/* This is so that one can refer to the enclosing
-		 * template, even if it has the same name as a member
-		 * of the template, if it has a !(arguments)
-		 */
-		tempdecl = ti->tempdecl;
-		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
-		    tempdecl = tempdecl->overroot; // then get the start
-		s = tempdecl;
-	    }
-	}
-
-	s = s->toAlias();
-
-	/* It should be a TemplateDeclaration, not some other symbol
-	 */
-	tempdecl = s->isTemplateDeclaration();
-	if (!tempdecl)
-	{
-	    if (!s->parent && global.errors)
-		return NULL;
-	    if (!s->parent && s->getType())
-	    {	Dsymbol *s2 = s->getType()->toDsymbol(sc);
-		if (!s2)
-		{
-		    error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
-		    return NULL;
-		}
-		s = s2;
-	    }
-#ifdef DEBUG
-	    //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars());
-#endif
-	    //assert(s->parent);
-	    TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
-	    if (ti &&
-		(ti->name == id ||
-		 ti->toAlias()->ident == id)
-		&&
-		ti->tempdecl)
-	    {
-		/* This is so that one can refer to the enclosing
-		 * template, even if it has the same name as a member
-		 * of the template, if it has a !(arguments)
-		 */
-		tempdecl = ti->tempdecl;
-		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
-		    tempdecl = tempdecl->overroot; // then get the start
-	    }
-	    else
-	    {
-		error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
-		return NULL;
-	    }
-	}
-    }
-    else
-	assert(tempdecl->isTemplateDeclaration());
-    return tempdecl;
-}
-
-TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc)
-{
-    /* Since there can be multiple TemplateDeclaration's with the same
-     * name, look for the best match.
-     */
-    TemplateDeclaration *td_ambig = NULL;
-    TemplateDeclaration *td_best = NULL;
-    MATCH m_best = MATCHnomatch;
-    Objects dedtypes;
-
-#if LOG
-    printf("TemplateInstance::findBestMatch()\n");
-#endif
-    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
-    {
-	MATCH m;
-
-//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]);
-
-	// If more arguments than parameters,
-	// then this is no match.
-	if (td->parameters->dim < tiargs->dim)
-	{
-	    if (!td->isVariadic())
-		continue;
-	}
-
-	dedtypes.setDim(td->parameters->dim);
-	dedtypes.zero();
-	if (!td->scope)
-	{
-	    error("forward reference to template declaration %s", td->toChars());
-	    return NULL;
-	}
-	m = td->matchWithInstance(this, &dedtypes, 0);
-	//printf("m = %d\n", m);
-	if (!m)			// no match at all
-	    continue;
-
-#if 1
-	if (m < m_best)
-	    goto Ltd_best;
-	if (m > m_best)
-	    goto Ltd;
-#else
-	if (!m_best)
-	    goto Ltd;
-#endif
-	{
-	// Disambiguate by picking the most specialized TemplateDeclaration
-	int c1 = td->leastAsSpecialized(td_best);
-	int c2 = td_best->leastAsSpecialized(td);
-	//printf("c1 = %d, c2 = %d\n", c1, c2);
-
-	if (c1 > c2)
-	    goto Ltd;
-	else if (c1 < c2)
-	    goto Ltd_best;
-	else
-	    goto Lambig;
-	}
-
-      Lambig:		// td_best and td are ambiguous
-	td_ambig = td;
-	continue;
-
-      Ltd_best:		// td_best is the best match so far
-	td_ambig = NULL;
-	continue;
-
-      Ltd:		// td is the new best match
-	td_ambig = NULL;
-	td_best = td;
-	m_best = m;
-	tdtypes.setDim(dedtypes.dim);
-	memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *));
-	continue;
-    }
-
-    if (!td_best)
-    {
-	error("%s does not match any template declaration", toChars());
-	return NULL;
-    }
-    if (td_ambig)
-    {
-	error("%s matches more than one template declaration, %s and %s",
-		toChars(), td_best->toChars(), td_ambig->toChars());
-    }
-
-    /* The best match is td_best
-     */
-    tempdecl = td_best;
-
-#if 0
-    /* Cast any value arguments to be same type as value parameter
-     */
-    for (size_t i = 0; i < tiargs->dim; i++)
-    {	Object *o = (Object *)tiargs->data[i];
-	Expression *ea = isExpression(o);	// value argument
-	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
-	assert(tp);
-	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-	if (tvp)
-	{
-	    assert(ea);
-	    ea = ea->castTo(tvp->valType);
-	    ea = ea->optimize(WANTvalue | WANTinterpret);
-	    tiargs->data[i] = (Object *)ea;
-	}
-    }
-#endif
-
-#if LOG
-    printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars());
-#endif
-    return tempdecl;
-}
-
-
-/*****************************************
- * Determines if a TemplateInstance will need a nested
- * generation of the TemplateDeclaration.
- */
-
-int TemplateInstance::isNested(Objects *args)
-{   int nested = 0;
-    //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars());
-
-    /* A nested instance happens when an argument references a local
-     * symbol that is on the stack.
-     */
-    for (size_t i = 0; i < args->dim; i++)
-    {   Object *o = (Object *)args->data[i];
-	Expression *ea = isExpression(o);
-	Dsymbol *sa = isDsymbol(o);
-	Tuple *va = isTuple(o);
-	if (ea)
-	{
-	    if (ea->op == TOKvar)
-	    {
-		sa = ((VarExp *)ea)->var;
-		goto Lsa;
-	    }
-	    if (ea->op == TOKfunction)
-	    {
-		sa = ((FuncExp *)ea)->fd;
-		goto Lsa;
-	    }
-	}
-	else if (sa)
-	{
-	  Lsa:
-	    Declaration *d = sa->isDeclaration();
-	    if (d && !d->isDataseg() &&
-#if V2
-		!(d->storage_class & STCmanifest) &&
-#endif
-		(!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
-		!isTemplateMixin())
-	    {
-		// if module level template
-		if (tempdecl->toParent()->isModule())
-		{   Dsymbol *dparent = d->toParent();
-		    if (!isnested)
-			isnested = dparent;
-		    else if (isnested != dparent)
-		    {
-			/* Select the more deeply nested of the two.
-			 * Error if one is not nested inside the other.
-			 */
-			for (Dsymbol *p = isnested; p; p = p->parent)
-			{
-			    if (p == dparent)
-				goto L1;	// isnested is most nested
-			}
-			for (Dsymbol *p = dparent; 1; p = p->parent)
-			{
-			    if (p == isnested)
-			    {	isnested = dparent;
-				goto L1;	// dparent is most nested
-			    }
-			}
-			error("is nested in both %s and %s", isnested->toChars(), dparent->toChars());
-		    }
-		  L1:
-		    //printf("\tnested inside %s\n", isnested->toChars());
-		    nested |= 1;
-		}
-		else
-		    error("cannot use local '%s' as template parameter", d->toChars());
-	    }
-	}
-	else if (va)
-	{
-	    nested |= isNested(&va->objects);
-	}
-    }
-    return nested;
-}
-
-/****************************************
- * This instance needs an identifier for name mangling purposes.
- * Create one by taking the template declaration name and adding
- * the type signature for it.
- */
-
-Identifier *TemplateInstance::genIdent()
-{   OutBuffer buf;
-    char *id;
-    Objects *args;
-
-    //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
-    id = tempdecl->ident->toChars();
-    buf.printf("__T%"PRIuSIZE"%s", strlen(id), id);
-    args = tiargs;
-    for (int i = 0; i < args->dim; i++)
-    {   Object *o = (Object *)args->data[i];
-	Type *ta = isType(o);
-	Expression *ea = isExpression(o);
-	Dsymbol *sa = isDsymbol(o);
-	Tuple *va = isTuple(o);
-	//printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va);
-	if (ta)
-	{
-	    buf.writeByte('T');
-	    if (ta->deco)
-		buf.writestring(ta->deco);
-	    else
-	    {
-#ifdef DEBUG
-		printf("ta = %d, %s\n", ta->ty, ta->toChars());
-#endif
-		assert(global.errors);
-	    }
-	}
-	else if (ea)
-	{   sinteger_t v;
-	    real_t r;
-
-	    if (ea->op == TOKvar)
-	    {
-		sa = ((VarExp *)ea)->var;
-		ea = NULL;
-		goto Lsa;
-	    }
-	    if (ea->op == TOKfunction)
-	    {
-		sa = ((FuncExp *)ea)->fd;
-		ea = NULL;
-		goto Lsa;
-	    }
-	    buf.writeByte('V');
-	    if (ea->op == TOKtuple)
-	    {	ea->error("tuple is not a valid template value argument");
-		continue;
-	    }
-#if 1
-	    /* Use deco that matches what it would be for a function parameter
-	     */
-	    buf.writestring(ea->type->deco);
-#else
-	    // Use type of parameter, not type of argument
-	    TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
-	    assert(tp);
-	    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-	    assert(tvp);
-	    buf.writestring(tvp->valType->deco);
-#endif
-	    ea->toMangleBuffer(&buf);
-	}
-	else if (sa)
-	{
-	  Lsa:
-	    buf.writeByte('S');
-	    Declaration *d = sa->isDeclaration();
-	    if (d && !d->type->deco)
-		error("forward reference of %s", d->toChars());
-	    else
-	    {
-		char *p = sa->mangle();
-        buf.printf("%"PRIuSIZE"%s", strlen(p), p);
-	    }
-	}
-	else if (va)
-	{
-	    assert(i + 1 == args->dim);		// must be last one
-	    args = &va->objects;
-	    i = -1;
-	}
-	else
-	    assert(0);
-    }
-    buf.writeByte('Z');
-    id = buf.toChars();
-    buf.data = NULL;
-    return new Identifier(id, TOKidentifier);
-}
-
-
-/****************************************************
- * Declare parameters of template instance, initialize them with the
- * template instance arguments.
- */
-
-void TemplateInstance::declareParameters(Scope *scope)
-{
-    //printf("TemplateInstance::declareParameters()\n");
-    for (int i = 0; i < tdtypes.dim; i++)
-    {
-	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
-	//Object *o = (Object *)tiargs->data[i];
-	Object *o = (Object *)tdtypes.data[i];
-
-	//printf("\ttdtypes[%d] = %p\n", i, o);
-	tempdecl->declareParameter(scope, tp, o);
-    }
-}
-
-
-void TemplateInstance::semantic2(Scope *sc)
-{   int i;
-
-    if (semanticdone >= 2)
-	return;
-    semanticdone = 2;
-#if LOG
-    printf("+TemplateInstance::semantic2('%s')\n", toChars());
-#endif
-    if (!errors && members)
-    {
-	sc = tempdecl->scope;
-	assert(sc);
-	sc = sc->push(argsym);
-	sc = sc->push(this);
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-#if LOG
-printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
-#endif
-	    s->semantic2(sc);
-	}
-	sc = sc->pop();
-	sc->pop();
-    }
-#if LOG
-    printf("-TemplateInstance::semantic2('%s')\n", toChars());
-#endif
-}
-
-void TemplateInstance::semantic3(Scope *sc)
-{   int i;
-
-#if LOG
-    printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone);
-#endif
-//if (toChars()[0] == 'D') *(char*)0=0;
-    if (semanticdone >= 3)
-	return;
-    semanticdone = 3;
-    if (!errors && members)
-    {
-	sc = tempdecl->scope;
-	sc = sc->push(argsym);
-	sc = sc->push(this);
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->semantic3(sc);
-	}
-	sc = sc->pop();
-	sc->pop();
-    }
-}
-
-void TemplateInstance::toObjFile()
-{   int i;
-
-#if LOG
-    printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this);
-#endif
-    if (!errors && members)
-    {
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->toObjFile();
-	}
-    }
-}
-
-void TemplateInstance::inlineScan()
-{   int i;
-
-#if LOG
-    printf("TemplateInstance::inlineScan('%s')\n", toChars());
-#endif
-    if (!errors && members)
-    {
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->inlineScan();
-	}
-    }
-}
-
-void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    int i;
-
-    Identifier *id = name;
-    buf->writestring(id->toChars());
-    buf->writestring("!(");
-    if (nest)
-	buf->writestring("...");
-    else
-    {
-	nest++;
-	Objects *args = tiargs;
-	for (i = 0; i < args->dim; i++)
-	{
-	    if (i)
-		buf->writeByte(',');
-	    Object *oarg = (Object *)args->data[i];
-	    ObjectToCBuffer(buf, hgs, oarg);
-	}
-	nest--;
-    }
-    buf->writeByte(')');
-}
-
-
-Dsymbol *TemplateInstance::toAlias()
-{
-#if LOG
-    printf("TemplateInstance::toAlias()\n");
-#endif
-    if (!inst)
-    {	error("cannot resolve forward reference");
-	return this;
-    }
-
-    if (inst != this)
-	return inst->toAlias();
-
-    if (aliasdecl)
-	return aliasdecl->toAlias();
-
-    return inst;
-}
-
-AliasDeclaration *TemplateInstance::isAliasDeclaration()
-{
-    return aliasdecl;
-}
-
-char *TemplateInstance::kind()
-{
-    return "template instance";
-}
-
-int TemplateInstance::oneMember(Dsymbol **ps)
-{
-    *ps = NULL;
-    return TRUE;
-}
-
-char *TemplateInstance::toChars()
-{
-    OutBuffer buf;
-    HdrGenState hgs;
-    char *s;
-
-    toCBuffer(&buf, &hgs);
-    s = buf.toChars();
-    buf.data = NULL;
-    return s;
-}
-
-/* ======================== TemplateMixin ================================ */
-
-TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual,
-	Array *idents, Objects *tiargs)
-	: TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1])
-{
-    //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
-    this->ident = ident;
-    this->tqual = tqual;
-    this->idents = idents;
-    this->tiargs = tiargs ? tiargs : new Objects();
-    this->scope = NULL;
-}
-
-Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s)
-{   TemplateMixin *tm;
-
-    Array *ids = new Array();
-    ids->setDim(idents->dim);
-    for (int i = 0; i < idents->dim; i++)
-    {	// Matches TypeQualified::syntaxCopyHelper()
-        Identifier *id = (Identifier *)idents->data[i];
-        if (id->dyncast() == DYNCAST_DSYMBOL)
-        {
-            TemplateInstance *ti = (TemplateInstance *)id;
-
-            ti = (TemplateInstance *)ti->syntaxCopy(NULL);
-            id = (Identifier *)ti;
-        }
-        ids->data[i] = id;
-    }
-
-    tm = new TemplateMixin(loc, ident,
-		(Type *)(tqual ? tqual->syntaxCopy() : NULL),
-		ids, tiargs);
-    TemplateInstance::syntaxCopy(tm);
-    return tm;
-}
-
-void TemplateMixin::semantic(Scope *sc)
-{
-#if LOG
-    printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
-    fflush(stdout);
-#endif
-    if (semanticdone &&
-	// This for when a class/struct contains mixin members, and
-	// is done over because of forward references
-	(!parent || !toParent()->isAggregateDeclaration()))
-    {
-#if LOG
-	printf("\tsemantic done\n");
-#endif
-	return;
-    }
-    if (!semanticdone)
-	semanticdone = 1;
-#if LOG
-    printf("\tdo semantic\n");
-#endif
-
-    Scope *scx = NULL;
-    if (scope)
-    {	sc = scope;
-	scx = scope;		// save so we don't make redundant copies
-	scope = NULL;
-    }
-
-    // Follow qualifications to find the TemplateDeclaration
-    if (!tempdecl)
-    {	Dsymbol *s;
-	int i;
-	Identifier *id;
-
-	if (tqual)
-	{   s = tqual->toDsymbol(sc);
-	    i = 0;
-	}
-	else
-	{
-	    i = 1;
-	    id = (Identifier *)idents->data[0];
-	    switch (id->dyncast())
-	    {
-		case DYNCAST_IDENTIFIER:
-		    s = sc->search(loc, id, NULL);
-		    break;
-
-		case DYNCAST_DSYMBOL:
-		{
-		    TemplateInstance *ti = (TemplateInstance *)id;
-		    ti->semantic(sc);
-		    s = ti;
-		    break;
-		}
-		default:
-		    assert(0);
-	    }
-	}
-
-	for (; i < idents->dim; i++)
-	{
-	    if (!s)
-		break;
-	    id = (Identifier *)idents->data[i];
-	    s = s->searchX(loc, sc, id);
-	}
-	if (!s)
-	{
-	    error("is not defined");
-	    inst = this;
-	    return;
-	}
-	tempdecl = s->toAlias()->isTemplateDeclaration();
-	if (!tempdecl)
-	{
-	    error("%s isn't a template", s->toChars());
-	    inst = this;
-	    return;
-	}
-    }
-
-    // Look for forward reference
-    assert(tempdecl);
-    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
-    {
-	if (!td->scope)
-	{
-	    /* Cannot handle forward references if mixin is a struct member,
-	     * because addField must happen during struct's semantic, not
-	     * during the mixin semantic.
-	     * runDeferred will re-run mixin's semantic outside of the struct's
-	     * semantic.
-	     */
-	    semanticdone = 0;
-	    AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
-	    if (ad)
-		ad->sizeok = 2;
-	    else
-	    {
-		// Forward reference
-		//printf("forward reference - deferring\n");
-		scope = scx ? scx : new Scope(*sc);
-		scope->setNoFree();
-		scope->module->addDeferredSemantic(this);
-	    }
-	    return;
-	}
-    }
-
-    // Run semantic on each argument, place results in tiargs[]
-    semanticTiargs(sc);
-
-    tempdecl = findBestMatch(sc);
-    if (!tempdecl)
-    {	inst = this;
-	return;		// error recovery
-    }
-
-    if (!ident)
-	ident = genIdent();
-
-    inst = this;
-    parent = sc->parent;
-
-    /* Detect recursive mixin instantiations.
-     */
-    for (Dsymbol *s = parent; s; s = s->parent)
-    {
-	//printf("\ts = '%s'\n", s->toChars());
-	TemplateMixin *tm = s->isTemplateMixin();
-	if (!tm || tempdecl != tm->tempdecl)
-	    continue;
-
-	for (int i = 0; i < tiargs->dim; i++)
-	{   Object *o = (Object *)tiargs->data[i];
-	    Type *ta = isType(o);
-	    Expression *ea = isExpression(o);
-	    Dsymbol *sa = isDsymbol(o);
-	    Object *tmo = (Object *)tm->tiargs->data[i];
-	    if (ta)
-	    {
-		Type *tmta = isType(tmo);
-		if (!tmta)
-		    goto Lcontinue;
-		if (!ta->equals(tmta))
-		    goto Lcontinue;
-	    }
-	    else if (ea)
-	    {	Expression *tme = isExpression(tmo);
-		if (!tme || !ea->equals(tme))
-		    goto Lcontinue;
-	    }
-	    else if (sa)
-	    {
-		Dsymbol *tmsa = isDsymbol(tmo);
-		if (sa != tmsa)
-		    goto Lcontinue;
-	    }
-	    else
-		assert(0);
-	}
-	error("recursive mixin instantiation");
-	return;
-
-    Lcontinue:
-	continue;
-    }
-
-    // Copy the syntax trees from the TemplateDeclaration
-    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
-    if (!members)
-	return;
-
-    symtab = new DsymbolTable();
-
-    for (Scope *sce = sc; 1; sce = sce->enclosing)
-    {
-	ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
-	if (sds)
-	{
-	    sds->importScope(this, PROTpublic);
-	    break;
-	}
-    }
-
-#if LOG
-    printf("\tcreate scope for template parameters '%s'\n", toChars());
-#endif
-    Scope *scy = sc;
-    scy = sc->push(this);
-    scy->parent = this;
-
-    argsym = new ScopeDsymbol();
-    argsym->parent = scy->parent;
-    Scope *scope = scy->push(argsym);
-
-    unsigned errorsave = global.errors;
-
-    // Declare each template parameter as an alias for the argument type
-    declareParameters(scope);
-
-    // Add members to enclosing scope, as well as this scope
-    for (unsigned i = 0; i < members->dim; i++)
-    {   Dsymbol *s;
-
-	s = (Dsymbol *)members->data[i];
-	s->addMember(scope, this, i);
-	//sc->insert(s);
-	//printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
-	//printf("s->parent = %s\n", s->parent->toChars());
-    }
-
-    // Do semantic() analysis on template instance members
-#if LOG
-    printf("\tdo semantic() on template instance members '%s'\n", toChars());
-#endif
-    Scope *sc2;
-    sc2 = scope->push(this);
-    sc2->offset = sc->offset;
-    for (int i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	s->semantic(sc2);
-    }
-    sc->offset = sc2->offset;
-
-    /* The problem is when to parse the initializer for a variable.
-     * Perhaps VarDeclaration::semantic() should do it like it does
-     * for initializers inside a function.
-     */
-//    if (sc->parent->isFuncDeclaration())
-
-	semantic2(sc2);
-
-    if (sc->func)
-    {
-	semantic3(sc2);
-    }
-
-    // Give additional context info if error occurred during instantiation
-    if (global.errors != errorsave)
-    {
-	error("error instantiating");
-    }
-
-    sc2->pop();
-
-    scope->pop();
-
-//    if (!isAnonymous())
-    {
-	scy->pop();
-    }
-#if LOG
-    printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
-#endif
-}
-
-void TemplateMixin::semantic2(Scope *sc)
-{   int i;
-
-    if (semanticdone >= 2)
-	return;
-    semanticdone = 2;
-#if LOG
-    printf("+TemplateMixin::semantic2('%s')\n", toChars());
-#endif
-    if (members)
-    {
-	assert(sc);
-	sc = sc->push(argsym);
-	sc = sc->push(this);
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-#if LOG
-	    printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
-#endif
-	    s->semantic2(sc);
-	}
-	sc = sc->pop();
-	sc->pop();
-    }
-#if LOG
-    printf("-TemplateMixin::semantic2('%s')\n", toChars());
-#endif
-}
-
-void TemplateMixin::semantic3(Scope *sc)
-{   int i;
-
-    if (semanticdone >= 3)
-	return;
-    semanticdone = 3;
-#if LOG
-    printf("TemplateMixin::semantic3('%s')\n", toChars());
-#endif
-    if (members)
-    {
-	sc = sc->push(argsym);
-	sc = sc->push(this);
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->semantic3(sc);
-	}
-	sc = sc->pop();
-	sc->pop();
-    }
-}
-
-void TemplateMixin::inlineScan()
-{
-    TemplateInstance::inlineScan();
-}
-
-char *TemplateMixin::kind()
-{
-    return "mixin";
-}
-
-int TemplateMixin::oneMember(Dsymbol **ps)
-{
-    return Dsymbol::oneMember(ps);
-}
-
-int TemplateMixin::hasPointers()
-{
-    //printf("TemplateMixin::hasPointers() %s\n", toChars());
-    for (size_t i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	//printf(" s = %s %s\n", s->kind(), s->toChars());
-	if (s->hasPointers())
-	{
-	    return 1;
-	}
-    }
-    return 0;
-}
-
-char *TemplateMixin::toChars()
-{
-    OutBuffer buf;
-    HdrGenState hgs;
-    char *s;
-
-    TemplateInstance::toCBuffer(&buf, &hgs);
-    s = buf.toChars();
-    buf.data = NULL;
-    return s;
-}
-
-void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("mixin ");
-    int i;
-    for (i = 0; i < idents->dim; i++)
-    {   Identifier *id = (Identifier *)idents->data[i];
-
-    	if (i)
-	    buf->writeByte('.');
-	buf->writestring(id->toChars());
-    }
-    buf->writestring("!(");
-    if (tiargs)
-    {
-        for (i = 0; i < tiargs->dim; i++)
-        {   if (i)
-                buf->writebyte(',');
-	    Object *oarg = (Object *)tiargs->data[i];
-	    Type *t = isType(oarg);
-	    Expression *e = isExpression(oarg);
-	    Dsymbol *s = isDsymbol(oarg);
-	    if (t)
-		t->toCBuffer(buf, NULL, hgs);
-	    else if (e)
-		e->toCBuffer(buf, hgs);
-	    else if (s)
-	    {
-		char *p = s->ident ? s->ident->toChars() : s->toChars();
-		buf->writestring(p);
-	    }
-	    else if (!oarg)
-	    {
-		buf->writestring("NULL");
-	    }
-	    else
-	    {
-		assert(0);
-	    }
-        }
-    }
-    buf->writebyte(')');
-    buf->writebyte(';');
-    buf->writenl();
-}
-
-
-void TemplateMixin::toObjFile()
-{
-    //printf("TemplateMixin::toObjFile('%s')\n", toChars());
-    TemplateInstance::toObjFile();
-}
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Handle template implementation
+
+#include <stdio.h>
+#include <assert.h>
+
+#if !IN_LLVM
+#if _WIN32
+#include <windows.h>
+long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
+#endif
+#endif
+
+#include "root.h"
+#include "mem.h"
+#include "stringtable.h"
+#include "mars.h"
+#include "identifier.h"
+#include "mtype.h"
+#include "template.h"
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "module.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "dsymbol.h"
+#include "hdrgen.h"
+
+#define LOG	0
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+
+Expression *isExpression(Object *o)
+{
+    //return dynamic_cast<Expression *>(o);
+    if (!o || o->dyncast() != DYNCAST_EXPRESSION)
+	return NULL;
+    return (Expression *)o;
+}
+
+Dsymbol *isDsymbol(Object *o)
+{
+    //return dynamic_cast<Dsymbol *>(o);
+    if (!o || o->dyncast() != DYNCAST_DSYMBOL)
+	return NULL;
+    return (Dsymbol *)o;
+}
+
+Type *isType(Object *o)
+{
+    //return dynamic_cast<Type *>(o);
+    if (!o || o->dyncast() != DYNCAST_TYPE)
+	return NULL;
+    return (Type *)o;
+}
+
+Tuple *isTuple(Object *o)
+{
+    //return dynamic_cast<Tuple *>(o);
+    if (!o || o->dyncast() != DYNCAST_TUPLE)
+	return NULL;
+    return (Tuple *)o;
+}
+
+
+/***********************
+ * Try to get arg as a type.
+ */
+
+Type *getType(Object *o)
+{
+    Type *t = isType(o);
+    if (!t)
+    {   Expression *e = isExpression(o);
+	if (e)
+	    t = e->type;
+    }
+    return t;
+}
+
+Dsymbol *getDsymbol(Object *oarg)
+{
+    Dsymbol *sa;
+    Expression *ea = isExpression(oarg);
+    if (ea)
+    {   // Try to convert Expression to symbol
+	if (ea->op == TOKvar)
+	    sa = ((VarExp *)ea)->var;
+	else if (ea->op == TOKfunction)
+	    sa = ((FuncExp *)ea)->fd;
+	else
+	    sa = NULL;
+    }
+    else
+    {   // Try to convert Type to symbol
+	Type *ta = isType(oarg);
+	if (ta)
+	    sa = ta->toDsymbol(NULL);
+	else
+	    sa = isDsymbol(oarg);	// if already a symbol
+    }
+    return sa;
+}
+
+/******************************
+ * If o1 matches o2, return 1.
+ * Else, return 0.
+ */
+
+int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc)
+{
+    Type *t1 = isType(o1);
+    Type *t2 = isType(o2);
+    Expression *e1 = isExpression(o1);
+    Expression *e2 = isExpression(o2);
+    Dsymbol *s1 = isDsymbol(o1);
+    Dsymbol *s2 = isDsymbol(o2);
+    Tuple *v1 = isTuple(o1);
+    Tuple *v2 = isTuple(o2);
+
+    //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2);
+
+    /* A proper implementation of the various equals() overrides
+     * should make it possible to just do o1->equals(o2), but
+     * we'll do that another day.
+     */
+
+    if (t1)
+    {
+	/* if t1 is an instance of ti, then give error
+	 * about recursive expansions.
+	 */
+	Dsymbol *s = t1->toDsymbol(sc);
+	if (s && s->parent)
+	{   TemplateInstance *ti1 = s->parent->isTemplateInstance();
+	    if (ti1 && ti1->tempdecl == tempdecl)
+	    {
+		for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing)
+		{
+		    if (sc1->scopesym == ti1)
+		    {
+			error("recursive template expansion for template argument %s", t1->toChars());
+			return 1;	// fake a match
+		    }
+		}
+	    }
+	}
+
+	if (!t2 || !t1->equals(t2))
+	    goto Lnomatch;
+    }
+    else if (e1)
+    {
+#if 0
+	if (e1 && e2)
+	{
+	    printf("match %d\n", e1->equals(e2));
+	    e1->print();
+	    e2->print();
+	    e1->type->print();
+	    e2->type->print();
+	}
+#endif
+	if (!e2)
+	    goto Lnomatch;
+	if (!e1->equals(e2))
+	    goto Lnomatch;
+    }
+    else if (s1)
+    {
+	//printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars());
+	if (!s2 || !s1->equals(s2) || s1->parent != s2->parent)
+	{
+	    goto Lnomatch;
+	}
+    }
+    else if (v1)
+    {
+	if (!v2)
+	    goto Lnomatch;
+	if (v1->objects.dim != v2->objects.dim)
+	    goto Lnomatch;
+	for (size_t i = 0; i < v1->objects.dim; i++)
+	{
+	    if (!match((Object *)v1->objects.data[i],
+		       (Object *)v2->objects.data[i],
+		       tempdecl, sc))
+		goto Lnomatch;
+	}
+    }
+    return 1;	// match
+Lnomatch:
+    return 0;	// nomatch;
+}
+
+/****************************************
+ */
+
+void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg)
+{
+    //printf("ObjectToCBuffer()\n");
+    Type *t = isType(oarg);
+    Expression *e = isExpression(oarg);
+    Dsymbol *s = isDsymbol(oarg);
+    Tuple *v = isTuple(oarg);
+    if (t)
+    {	//printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
+	t->toCBuffer(buf, NULL, hgs);
+    }
+    else if (e)
+	e->toCBuffer(buf, hgs);
+    else if (s)
+    {
+	char *p = s->ident ? s->ident->toChars() : s->toChars();
+	buf->writestring(p);
+    }
+    else if (v)
+    {
+	Objects *args = &v->objects;
+	for (size_t i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *o = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, o);
+	}
+    }
+    else if (!oarg)
+    {
+	buf->writestring("NULL");
+    }
+    else
+    {
+#ifdef DEBUG
+	printf("bad Object = %p\n", oarg);
+#endif
+	assert(0);
+    }
+}
+
+
+
+/* ======================== TemplateDeclaration ============================= */
+
+TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs)
+    : ScopeDsymbol(id)
+{
+#if LOG
+    printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars());
+#endif
+#if 0
+    if (parameters)
+	for (int i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    //printf("\tparameter[%d] = %p\n", i, tp);
+	    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+	    if (ttp)
+	    {
+		printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+	    }
+	}
+#endif
+    this->loc = loc;
+    this->parameters = parameters;
+    this->origParameters = parameters;
+    this->members = decldefs;
+    this->overnext = NULL;
+    this->overroot = NULL;
+    this->scope = NULL;
+    this->onemember = NULL;
+}
+
+Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
+{
+    //printf("TemplateDeclaration::syntaxCopy()\n");
+    TemplateDeclaration *td;
+    TemplateParameters *p;
+    Array *d;
+
+    p = NULL;
+    if (parameters)
+    {
+	p = new TemplateParameters();
+	p->setDim(parameters->dim);
+	for (int i = 0; i < p->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    p->data[i] = (void *)tp->syntaxCopy();
+	}
+    }
+    d = Dsymbol::arraySyntaxCopy(members);
+    td = new TemplateDeclaration(loc, ident, p, d);
+    return td;
+}
+
+void TemplateDeclaration::semantic(Scope *sc)
+{
+#if LOG
+    printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars());
+#endif
+    if (scope)
+	return;		// semantic() already run
+
+    if (sc->func)
+    {
+	error("cannot declare template at function scope %s", sc->func->toChars());
+    }
+
+    if (/*global.params.useArrayBounds &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleArray();
+    }
+
+    if (/*global.params.useAssert &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleAssert();
+    }
+
+    /* Remember Scope for later instantiations, but make
+     * a copy since attributes can change.
+     */
+    this->scope = new Scope(*sc);
+    this->scope->setNoFree();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = sc->parent;
+    Scope *paramscope = sc->push(paramsym);
+    paramscope->parameterSpecialization = 1;
+
+    if (global.params.doDocComments)
+    {
+	origParameters = new TemplateParameters();
+	origParameters->setDim(parameters->dim);
+	for (int i = 0; i < parameters->dim; i++)
+	{
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    origParameters->data[i] = (void *)tp->syntaxCopy();
+	}
+    }
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->declareParameter(paramscope);
+    }
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->semantic(paramscope);
+	if (i + 1 != parameters->dim && tp->isTemplateTupleParameter())
+	    error("template tuple parameter must be last one");
+    }
+
+    paramscope->pop();
+
+    if (members)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s))
+	{
+	    if (s && s->ident && s->ident->equals(ident))
+	    {
+		onemember = s;
+		s->parent = this;
+	    }
+	}
+    }
+
+    /* BUG: should check:
+     *	o no virtual functions or non-static data members of classes
+     */
+}
+
+const char *TemplateDeclaration::kind()
+{
+    return (onemember && onemember->isAggregateDeclaration())
+		? onemember->kind()
+		: (char *)"template";
+}
+
+/**********************************
+ * Overload existing TemplateDeclaration 'this' with the new one 's'.
+ * Return !=0 if successful; i.e. no conflict.
+ */
+
+int TemplateDeclaration::overloadInsert(Dsymbol *s)
+{
+    TemplateDeclaration **pf;
+    TemplateDeclaration *f;
+
+#if LOG
+    printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars());
+#endif
+    f = s->isTemplateDeclaration();
+    if (!f)
+	return FALSE;
+    TemplateDeclaration *pthis = this;
+    for (pf = &pthis; *pf; pf = &(*pf)->overnext)
+    {
+#if 0
+	// Conflict if TemplateParameter's match
+	// Will get caught anyway later with TemplateInstance, but
+	// should check it now.
+	TemplateDeclaration *f2 = *pf;
+
+	if (f->parameters->dim != f2->parameters->dim)
+	    goto Lcontinue;
+
+	for (int i = 0; i < f->parameters->dim; i++)
+	{   TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i];
+	    TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i];
+
+	    if (!p1->overloadMatch(p2))
+		goto Lcontinue;
+	}
+
+#if LOG
+	printf("\tfalse: conflict\n");
+#endif
+	return FALSE;
+
+     Lcontinue:
+	;
+#endif
+    }
+
+    f->overroot = this;
+    *pf = f;
+#if LOG
+    printf("\ttrue: no conflict\n");
+#endif
+    return TRUE;
+}
+
+/***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Input:
+ *	flag	1: don't do semantic() because of dummy types
+ *		2: don't change types in matchArg()
+ * Output:
+ *	dedtypes	deduced arguments
+ * Return match level.
+ */
+
+MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti,
+	Objects *dedtypes, int flag)
+{   MATCH m;
+    int dedtypes_dim = dedtypes->dim;
+
+#define LOGM 0
+#if LOGM
+    printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag);
+#endif
+
+#if 0
+    printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim);
+    if (ti->tiargs->dim)
+	printf("ti->tiargs->dim = %d, [0] = %p\n",
+	    ti->tiargs->dim,
+	    ti->tiargs->data[0]);
+#endif
+    dedtypes->zero();
+
+    int parameters_dim = parameters->dim;
+    int variadic = isVariadic() != NULL;
+
+    // If more arguments than parameters, no match
+    if (ti->tiargs->dim > parameters_dim && !variadic)
+    {
+#if LOGM
+	printf(" no match: more arguments than parameters\n");
+#endif
+	return MATCHnomatch;
+    }
+
+    assert(dedtypes_dim == parameters_dim);
+    assert(dedtypes_dim >= ti->tiargs->dim || variadic);
+
+    // Set up scope for parameters
+    assert((size_t)scope > 0x10000);
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    // Attempt type deduction
+    m = MATCHexact;
+    for (int i = 0; i < dedtypes_dim; i++)
+    {	MATCH m2;
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	Declaration *sparam;
+
+	//printf("\targument [%d]\n", i);
+#if LOGM
+	//printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
+	TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+	if (ttp)
+	    printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+#endif
+
+#if DMDV1
+	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+#else
+	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0);
+
+#endif
+	//printf("\tm2 = %d\n", m2);
+
+	if (m2 == MATCHnomatch)
+	{
+#if 0
+	    printf("\tmatchArg() for parameter %i failed\n", i);
+#endif
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+
+	if (!flag)
+	    sparam->semantic(paramscope);
+	if (!paramscope->insert(sparam))
+	    goto Lnomatch;
+    }
+
+    if (!flag)
+    {
+	// Any parameter left without a type gets the type of its corresponding arg
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    if (!dedtypes->data[i])
+	    {   assert(i < ti->tiargs->dim);
+		dedtypes->data[i] = ti->tiargs->data[i];
+	    }
+	}
+    }
+
+#if LOGM
+    // Print out the results
+    printf("--------------------------\n");
+    printf("template %s\n", toChars());
+    printf("instance %s\n", ti->toChars());
+    if (m)
+    {
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    Object *oarg;
+
+	    printf(" [%d]", i);
+
+	    if (i < ti->tiargs->dim)
+		oarg = (Object *)ti->tiargs->data[i];
+	    else
+		oarg = NULL;
+	    tp->print(oarg, (Object *)dedtypes->data[i]);
+	}
+    }
+    else
+	goto Lnomatch;
+#endif
+
+#if LOGM
+    printf(" match = %d\n", m);
+#endif
+    goto Lret;
+
+Lnomatch:
+#if LOGM
+    printf(" no match\n");
+#endif
+    m = MATCHnomatch;
+
+Lret:
+    paramscope->pop();
+#if LOGM
+    printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
+#endif
+    return m;
+}
+
+/********************************************
+ * Determine partial specialization order of 'this' vs td2.
+ * Returns:
+ *	1	this is at least as specialized as td2
+ *	0	td2 is more specialized than this
+ */
+
+int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2)
+{
+    /* This works by taking the template parameters to this template
+     * declaration and feeding them to td2 as if it were a template
+     * instance.
+     * If it works, then this template is at least as specialized
+     * as td2.
+     */
+
+    TemplateInstance ti(0, ident);	// create dummy template instance
+    Objects dedtypes;
+
+#define LOG_LEASTAS	0
+
+#if LOG_LEASTAS
+    printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars());
+#endif
+
+    // Set type arguments to dummy template instance to be types
+    // generated from the parameters to this template declaration
+    ti.tiargs = new Objects();
+    ti.tiargs->setDim(parameters->dim);
+    for (int i = 0; i < ti.tiargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	void *p = tp->dummyArg();
+	if (p)
+	    ti.tiargs->data[i] = p;
+	else
+	    ti.tiargs->setDim(i);
+    }
+
+    // Temporary Array to hold deduced types
+    //dedtypes.setDim(parameters->dim);
+    dedtypes.setDim(td2->parameters->dim);
+
+    // Attempt a type deduction
+    if (td2->matchWithInstance(&ti, &dedtypes, 1))
+    {
+	/* A non-variadic template is more specialized than a
+	 * variadic one.
+	 */
+	if (isVariadic() && !td2->isVariadic())
+	    goto L1;
+
+#if LOG_LEASTAS
+	printf("  matches, so is least as specialized\n");
+#endif
+	return 1;
+    }
+  L1:
+#if LOG_LEASTAS
+    printf("  doesn't match, so is not as specialized\n");
+#endif
+    return 0;
+}
+
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ *	targsi		Expression/Type initial list of template arguments
+ *	fargs		arguments to function
+ * Output:
+ *	dedargs		Expression/Type deduced template arguments
+ * Returns:
+ *	match level
+ */
+
+MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs,
+	Objects *dedargs)
+{
+    size_t i;
+    size_t nfparams;
+    size_t nfargs;
+    size_t nargsi;		// array size of targsi
+    int fptupindex = -1;
+    int tuple_dim = 0;
+    MATCH match = MATCHexact;
+    FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration();
+    TypeFunction *fdtype;		// type of fd
+    TemplateTupleParameter *tp;
+    Objects dedtypes;	// for T:T*, the dedargs is the T*, dedtypes is the T
+
+#if 0
+    printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
+    for (i = 0; i < fargs->dim; i++)
+    {	Expression *e = (Expression *)fargs->data[i];
+	printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
+    }
+#endif
+
+    assert((size_t)scope > 0x10000);
+
+    dedargs->setDim(parameters->dim);
+    dedargs->zero();
+
+    dedtypes.setDim(parameters->dim);
+    dedtypes.zero();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    tp = isVariadic();
+
+    nargsi = 0;
+    if (targsi)
+    {	// Set initial template arguments
+
+	nargsi = targsi->dim;
+	if (nargsi > parameters->dim)
+	{   if (!tp)
+		goto Lnomatch;
+	    dedargs->setDim(nargsi);
+	    dedargs->zero();
+	}
+
+	memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data));
+
+	for (i = 0; i < nargsi; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    MATCH m;
+	    Declaration *sparam;
+
+	    m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
+	    //printf("\tdeduceType m = %d\n", m);
+	    if (m == MATCHnomatch)
+		goto Lnomatch;
+	    if (m < match)
+		match = m;
+
+	    sparam->semantic(paramscope);
+	    if (!paramscope->insert(sparam))
+		goto Lnomatch;
+	}
+    }
+
+    assert(fd->type->ty == Tfunction);
+    fdtype = (TypeFunction *)fd->type;
+
+    nfparams = Argument::dim(fdtype->parameters); // number of function parameters
+    nfargs = fargs->dim;		// number of function arguments
+
+    /* Check for match of function arguments with variadic template
+     * parameter, such as:
+     *
+     * template Foo(T, A...) { void Foo(T t, A a); }
+     * void main() { Foo(1,2,3); }
+     */
+    tp = isVariadic();
+    if (tp)				// if variadic
+    {
+	if (nfparams == 0)		// if no function parameters
+	{
+	    Tuple *t = new Tuple();
+	    //printf("t = %p\n", t);
+	    dedargs->data[parameters->dim - 1] = (void *)t;
+	    goto L2;
+	}
+	else if (nfargs < nfparams - 1)
+	    goto L1;
+	else
+	{
+	    /* Figure out which of the function parameters matches
+	     * the tuple template parameter. Do this by matching
+	     * type identifiers.
+	     * Set the index of this function parameter to fptupindex.
+	     */
+	    for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
+	    {
+		Argument *fparam = (Argument *)fdtype->parameters->data[fptupindex];
+		if (fparam->type->ty != Tident)
+		    continue;
+		TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+		if (!tp->ident->equals(tid->ident) || tid->idents.dim)
+		    continue;
+
+		if (fdtype->varargs)	// variadic function doesn't
+		    goto Lnomatch;	// go with variadic template
+
+		/* The types of the function arguments
+		 * now form the tuple argument.
+		 */
+		Tuple *t = new Tuple();
+		dedargs->data[parameters->dim - 1] = (void *)t;
+
+		tuple_dim = nfargs - (nfparams - 1);
+		t->objects.setDim(tuple_dim);
+		for (i = 0; i < tuple_dim; i++)
+		{   Expression *farg = (Expression *)fargs->data[fptupindex + i];
+		    t->objects.data[i] = (void *)farg->type;
+		}
+		goto L2;
+	    }
+	    fptupindex = -1;
+	}
+    }
+
+L1:
+    if (nfparams == nfargs)
+	;
+    else if (nfargs > nfparams)
+    {
+	if (fdtype->varargs == 0)
+	    goto Lnomatch;		// too many args, no match
+	match = MATCHconvert;		// match ... with a conversion
+    }
+
+L2:
+    // Loop through the function parameters
+    for (i = 0; i < nfparams; i++)
+    {
+	/* Skip over function parameters which wound up
+	 * as part of a template tuple parameter.
+	 */
+	if (i == fptupindex)
+	{   if (fptupindex == nfparams - 1)
+		break;
+	    i += tuple_dim - 1;
+	    continue;
+	}
+
+	Argument *fparam = Argument::getNth(fdtype->parameters, i);
+
+	if (i >= nfargs)		// if not enough arguments
+	{
+	    if (fparam->defaultArg)
+	    {	/* Default arguments do not participate in template argument
+		 * deduction.
+		 */
+		goto Lmatch;
+	    }
+	}
+	else
+	{   Expression *farg = (Expression *)fargs->data[i];
+#if 0
+	    printf("\tfarg->type   = %s\n", farg->type->toChars());
+	    printf("\tfparam->type = %s\n", fparam->type->toChars());
+#endif
+
+	    MATCH m;
+	    m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes);
+	    //printf("\tdeduceType m = %d\n", m);
+
+	    /* If no match, see if there's a conversion to a delegate
+	     */
+	    if (!m && fparam->type->toBasetype()->ty == Tdelegate)
+	    {
+		TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype();
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
+		{
+		    m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes);
+		    if (!m && tf->next->toBasetype()->ty == Tvoid)
+			m = MATCHconvert;
+		}
+		//printf("\tm2 = %d\n", m);
+	    }
+
+	    if (m)
+	    {	if (m < match)
+		    match = m;		// pick worst match
+		continue;
+	    }
+	}
+
+	/* The following code for variadic arguments closely
+	 * matches TypeFunction::callMatch()
+	 */
+	if (!(fdtype->varargs == 2 && i + 1 == nfparams))
+	    goto Lnomatch;
+
+	/* Check for match with function parameter T...
+	 */
+	Type *tb = fparam->type->toBasetype();
+	switch (tb->ty)
+	{
+	    // Perhaps we can do better with this, see TypeFunction::callMatch()
+	    case Tsarray:
+	    {	TypeSArray *tsa = (TypeSArray *)tb;
+		integer_t sz = tsa->dim->toInteger();
+		if (sz != nfargs - i)
+		    goto Lnomatch;
+	    }
+	    case Tarray:
+	    {   TypeArray *ta = (TypeArray *)tb;
+		for (; i < nfargs; i++)
+		{
+		    Expression *arg = (Expression *)fargs->data[i];
+		    assert(arg);
+		    MATCH m;
+		    /* If lazy array of delegates,
+		     * convert arg(s) to delegate(s)
+		     */
+		    Type *tret = fparam->isLazyArray();
+		    if (tret)
+		    {
+			if (ta->next->equals(arg->type))
+			{   m = MATCHexact;
+			}
+			else
+			{
+			    m = arg->implicitConvTo(tret);
+			    if (m == MATCHnomatch)
+			    {
+				if (tret->toBasetype()->ty == Tvoid)
+				    m = MATCHconvert;
+			    }
+			}
+		    }
+		    else
+		    {
+			m = arg->type->deduceType(scope, ta->next, parameters, &dedtypes);
+			//m = arg->implicitConvTo(ta->next);
+		    }
+		    if (m == MATCHnomatch)
+			goto Lnomatch;
+		    if (m < match)
+			match = m;
+		}
+		goto Lmatch;
+	    }
+	    case Tclass:
+	    case Tident:
+		goto Lmatch;
+
+	    default:
+		goto Lnomatch;
+	}
+    }
+
+Lmatch:
+
+    /* Fill in any missing arguments with their defaults.
+     */
+    for (i = nargsi; i < dedargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	//printf("tp[%d] = %s\n", i, tp->ident->toChars());
+	/* For T:T*, the dedargs is the T*, dedtypes is the T
+	 * But for function templates, we really need them to match
+	 */
+	Object *oarg = (Object *)dedargs->data[i];
+	Object *oded = (Object *)dedtypes.data[i];
+	//printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+	if (!oarg)
+	{
+	    if (oded)
+	    {
+		if (tp->specialization())
+		{   /* The specialization can work as long as afterwards
+		     * the oded == oarg
+		     */
+		    Declaration *sparam;
+		    dedargs->data[i] = (void *)oded;
+		    MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
+		    //printf("m2 = %d\n", m2);
+		    if (!m2)
+			goto Lnomatch;
+		    if (m2 < match)
+			match = m2;		// pick worst match
+		    if (dedtypes.data[i] != oded)
+			error("specialization not allowed for deduced parameter %s", tp->ident->toChars());
+		}
+	    }
+	    else
+	    {	oded = tp->defaultArg(paramscope);
+		if (!oded)
+		    goto Lnomatch;
+	    }
+	    declareParameter(paramscope, tp, oded);
+	    dedargs->data[i] = (void *)oded;
+	}
+    }
+
+#if 0
+    for (i = 0; i < dedargs->dim; i++)
+    {	Type *t = (Type *)dedargs->data[i];
+	printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars());
+    }
+#endif
+
+    paramscope->pop();
+    //printf("\tmatch %d\n", match);
+    return match;
+
+Lnomatch:
+    paramscope->pop();
+    //printf("\tnomatch\n");
+    return MATCHnomatch;
+}
+
+/**************************************************
+ * Declare template parameter tp with value o.
+ */
+
+void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o)
+{
+    //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
+
+    Type *targ = isType(o);
+    Expression *ea = isExpression(o);
+    Dsymbol *sa = isDsymbol(o);
+    Tuple *va = isTuple(o);
+
+    Dsymbol *s;
+
+    if (targ)
+    {
+	//printf("type %s\n", targ->toChars());
+	s = new AliasDeclaration(0, tp->ident, targ);
+    }
+    else if (sa)
+    {
+	//printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
+	s = new AliasDeclaration(0, tp->ident, sa);
+    }
+    else if (ea)
+    {
+	// tdtypes.data[i] always matches ea here
+	Initializer *init = new ExpInitializer(loc, ea);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	assert(tvp);
+
+	VarDeclaration *v = new VarDeclaration(loc, tvp->valType, tp->ident, init);
+	v->storage_class = STCconst;
+	s = v;
+    }
+    else if (va)
+    {
+	//printf("\ttuple\n");
+	s = new TupleDeclaration(loc, tp->ident, &va->objects);
+    }
+    else
+    {
+#ifdef DEBUG
+	o->print();
+#endif
+	assert(0);
+    }
+    if (!sc->insert(s))
+	error("declaration %s is already defined", tp->ident->toChars());
+    s->semantic(sc);
+}
+
+/**************************************
+ * Determine if TemplateDeclaration is variadic.
+ */
+
+TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
+{   size_t dim = parameters->dim;
+    TemplateTupleParameter *tp = NULL;
+
+    if (dim)
+	tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter();
+    return tp;
+}
+
+TemplateTupleParameter *TemplateDeclaration::isVariadic()
+{
+    return ::isVariadic(parameters);
+}
+
+/***********************************
+ * We can overload templates.
+ */
+
+int TemplateDeclaration::isOverloadable()
+{
+    return 1;
+}
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return that function.
+ * If no match, give error message and return NULL.
+ * Input:
+ *	sc		instantiation scope
+ *	loc		instantiation location
+ *	targsi		initial list of template arguments
+ *	fargs		arguments to function
+ */
+
+FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
+	Objects *targsi, Expressions *fargs)
+{
+    MATCH m_best = MATCHnomatch;
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    Objects *tdargs = new Objects();
+    TemplateInstance *ti;
+    FuncDeclaration *fd;
+
+#if 0
+    printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars());
+    printf("    targsi:\n");
+    if (targsi)
+    {	for (int i = 0; i < targsi->dim; i++)
+	{   Object *arg = (Object *)targsi->data[i];
+	    printf("\t%s\n", arg->toChars());
+	}
+    }
+    printf("    fargs:\n");
+    for (int i = 0; i < fargs->dim; i++)
+    {	Expression *arg = (Expression *)fargs->data[i];
+	printf("\t%s %s\n", arg->type->toChars(), arg->toChars());
+	//printf("\tty = %d\n", arg->type->ty);
+    }
+#endif
+
+    for (TemplateDeclaration *td = this; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    error("forward reference to template %s", td->toChars());
+	    goto Lerror;
+	}
+	if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration())
+	{
+	    error("is not a function template");
+	    goto Lerror;
+	}
+
+	MATCH m;
+	Objects dedargs;
+
+	m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs);
+	//printf("deduceFunctionTemplateMatch = %d\n", m);
+	if (!m)			// if no match
+	    continue;
+
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	int c1 = td->leastAsSpecialized(td_best);
+	int c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 > c2)
+	    goto Ltd;
+	else if (c1 < c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	assert((size_t)td->scope > 0x10000);
+	td_best = td;
+	m_best = m;
+	tdargs->setDim(dedargs.dim);
+	memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *));
+	continue;
+    }
+    if (!td_best)
+    {
+	error(loc, "does not match any template declaration");
+	goto Lerror;
+    }
+    if (td_ambig)
+    {
+	error(loc, "%s matches more than one function template declaration, %s and %s",
+		toChars(), td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best with arguments tdargs.
+     * Now instantiate the template.
+     */
+    assert((size_t)td_best->scope > 0x10000);
+    ti = new TemplateInstance(loc, td_best, tdargs);
+    ti->semantic(sc);
+    fd = ti->toAlias()->isFuncDeclaration();
+    if (!fd)
+	goto Lerror;
+    return fd;
+
+  Lerror:
+    {
+	OutBuffer buf;
+	HdrGenState hgs;
+
+	argExpTypesToCBuffer(&buf, fargs, &hgs);
+	error(loc, "cannot deduce template function from argument types (%s)",
+		buf.toChars());
+	return NULL;
+    }
+}
+
+void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+#if 0 // Should handle template functions
+    if (onemember && onemember->isFuncDeclaration())
+	buf->writestring("foo ");
+#endif
+    buf->writestring(kind());
+    buf->writeByte(' ');
+    buf->writestring(ident->toChars());
+    buf->writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (hgs->ddoc)
+	    tp = (TemplateParameter *)origParameters->data[i];
+	if (i)
+	    buf->writeByte(',');
+	tp->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(')');
+
+    if (hgs->hdrgen)
+    {
+	hgs->tpltMember++;
+	buf->writenl();
+	buf->writebyte('{');
+	buf->writenl();
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writebyte('}');
+	buf->writenl();
+	hgs->tpltMember--;
+    }
+}
+
+
+char *TemplateDeclaration::toChars()
+{   OutBuffer buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf.writestring(ident->toChars());
+    buf.writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (i)
+	    buf.writeByte(',');
+	tp->toCBuffer(&buf, &hgs);
+    }
+    buf.writeByte(')');
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return -1 if not found.
+ */
+
+int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
+{
+    for (size_t i = 0; i < parameters->dim; i++)
+    {   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	if (tp->ident->equals(id))
+	    return i;
+    }
+    return -1;
+}
+
+int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
+{
+    assert(tparam->ty == Tident);
+    TypeIdentifier *tident = (TypeIdentifier *)tparam;
+    //printf("\ttident = '%s'\n", tident->toChars());
+    if (tident->idents.dim == 0)
+    {
+	return templateIdentifierLookup(tident->ident, parameters);
+    }
+    return -1;
+}
+
+/* These form the heart of template argument deduction.
+ * Given 'this' being the type argument to the template instance,
+ * it is matched against the template declaration parameter specialization
+ * 'tparam' to determine the type to be used for the parameter.
+ * Example:
+ *	template Foo(T:T*)	// template declaration
+ *	Foo!(int*)		// template instantiation
+ * Input:
+ *	this = int*
+ *	tparam = T
+ *	parameters = [ T:T* ]	// Array of TemplateParameter's
+ * Output:
+ *	dedtypes = [ int ]	// Array of Expression/Type's
+ */
+
+MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+    //printf("Type::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+    if (!tparam)
+	goto Lnomatch;
+
+    if (this == tparam)
+	goto Lexact;
+
+    if (tparam->ty == Tident)
+    {
+	// Determine which parameter tparam is
+	int i = templateParameterLookup(tparam, parameters);
+	if (i == -1)
+	{
+	    if (!sc)
+		goto Lnomatch;
+
+	    /* Need a loc to go with the semantic routine.
+	     */
+	    Loc loc;
+	    if (parameters->dim)
+	    {
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[0];
+		loc = tp->loc;
+	    }
+
+	    /* BUG: what if tparam is a template instance, that
+	     * has as an argument another Tident?
+	     */
+	    tparam = tparam->semantic(loc, sc);
+	    assert(tparam->ty != Tident);
+	    return deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	// Found the corresponding parameter tp
+	if (!tp->isTemplateTypeParameter())
+	    goto Lnomatch;
+	Type *at = (Type *)dedtypes->data[i];
+	if (!at)
+	{
+	    dedtypes->data[i] = (void *)this;
+	    goto Lexact;
+	}
+	if (equals(at))
+	    goto Lexact;
+	else if (ty == Tclass && at->ty == Tclass)
+	{
+	    return (MATCH) implicitConvTo(at);
+	}
+	else if (ty == Tsarray && at->ty == Tarray &&
+	    nextOf()->equals(at->nextOf()))
+	{
+	    goto Lexact;
+	}
+	else
+	    goto Lnomatch;
+    }
+
+    if (ty != tparam->ty)
+	return implicitConvTo(tparam);
+//	goto Lnomatch;
+
+    if (nextOf())
+	return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+
+Lexact:
+    return MATCHexact;
+
+Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+#if 0
+    printf("TypeSArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+    // Extra check that array dimensions must match
+    if (tparam)
+    {
+	if (tparam->ty == Tsarray)
+	{
+	    TypeSArray *tp = (TypeSArray *)tparam;
+
+	    if (tp->dim->op == TOKvar &&
+		((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter)
+	    {	int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters);
+		// This code matches code in TypeInstance::deduceType()
+		if (i == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+		TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+		if (!tvp)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[i];
+		if (e)
+		{
+		    if (!dim->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tvp->valType->semantic(0, sc);
+		    MATCH m = (MATCH)dim->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[i] = dim;
+		}
+	    }
+	    else if (dim->toInteger() != tp->dim->toInteger())
+		return MATCHnomatch;
+	}
+	else if (tparam->ty == Taarray)
+	{
+	    TypeAArray *tp = (TypeAArray *)tparam;
+	    if (tp->index->ty == Tident)
+	    {	TypeIdentifier *tident = (TypeIdentifier *)tp->index;
+
+		if (tident->idents.dim == 0)
+		{   Identifier *id = tident->ident;
+
+		    for (size_t i = 0; i < parameters->dim; i++)
+		    {
+			TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+			if (tp->ident->equals(id))
+			{   // Found the corresponding template parameter
+			    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+			    if (!tvp || !tvp->valType->isintegral())
+				goto Lnomatch;
+
+			    if (dedtypes->data[i])
+			    {
+				if (!dim->equals((Object *)dedtypes->data[i]))
+				    goto Lnomatch;
+			    }
+			    else
+			    {	dedtypes->data[i] = (void *)dim;
+			    }
+			    return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+			}
+		    }
+		}
+	    }
+	}
+	else if (tparam->ty == Tarray)
+	{   MATCH m;
+
+	    m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+	    if (m == MATCHexact)
+		m = MATCHconvert;
+	    return m;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+  Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+#if 0
+    printf("TypeAArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+    // Extra check that index type must match
+    if (tparam && tparam->ty == Taarray)
+    {
+	TypeAArray *tp = (TypeAArray *)tparam;
+	if (!index->deduceType(sc, tp->index, parameters, dedtypes))
+	{
+	    return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeFunction::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check that function characteristics must match
+    if (tparam && tparam->ty == Tfunction)
+    {
+	TypeFunction *tp = (TypeFunction *)tparam;
+	if (varargs != tp->varargs ||
+	    linkage != tp->linkage)
+	    return MATCHnomatch;
+
+	size_t nfargs = Argument::dim(this->parameters);
+	size_t nfparams = Argument::dim(tp->parameters);
+
+	/* See if tuple match
+	 */
+	if (nfparams > 0 && nfargs >= nfparams - 1)
+	{
+	    /* See if 'A' of the template parameter matches 'A'
+	     * of the type of the last function parameter.
+	     */
+	    Argument *fparam = (Argument *)tp->parameters->data[nfparams - 1];
+	    if (fparam->type->ty != Tident)
+		goto L1;
+	    TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+	    if (tid->idents.dim)
+		goto L1;
+
+	    /* Look through parameters to find tuple matching tid->ident
+	     */
+	    size_t tupi = 0;
+	    for (; 1; tupi++)
+	    {	if (tupi == parameters->dim)
+		    goto L1;
+		TemplateParameter *t = (TemplateParameter *)parameters->data[tupi];
+		TemplateTupleParameter *tup = t->isTemplateTupleParameter();
+		if (tup && tup->ident->equals(tid->ident))
+		    break;
+	    }
+
+	    /* The types of the function arguments [nfparams - 1 .. nfargs]
+	     * now form the tuple argument.
+	     */
+	    int tuple_dim = nfargs - (nfparams - 1);
+
+	    /* See if existing tuple, and whether it matches or not
+	     */
+	    Object *o = (Object *)dedtypes->data[tupi];
+	    if (o)
+	    {	// Existing deduced argument must be a tuple, and must match
+		Tuple *t = isTuple(o);
+		if (!t || t->objects.dim != tuple_dim)
+		    return MATCHnomatch;
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    if (!arg->type->equals((Object *)t->objects.data[i]))
+			return MATCHnomatch;
+		}
+	    }
+	    else
+	    {	// Create new tuple
+		Tuple *t = new Tuple();
+		t->objects.setDim(tuple_dim);
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    t->objects.data[i] = (void *)arg->type;
+		}
+		dedtypes->data[tupi] = (void *)t;
+	    }
+	    nfparams--;	// don't consider the last parameter for type deduction
+	    goto L2;
+	}
+
+    L1:
+	if (nfargs != nfparams)
+	    return MATCHnomatch;
+    L2:
+	for (size_t i = 0; i < nfparams; i++)
+	{
+	    Argument *a = Argument::getNth(this->parameters, i);
+	    Argument *ap = Argument::getNth(tp->parameters, i);
+	    if (a->storageClass != ap->storageClass ||
+		!a->type->deduceType(sc, ap->type, parameters, dedtypes))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tident)
+    {
+	TypeIdentifier *tp = (TypeIdentifier *)tparam;
+
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id1 = (Identifier *)idents.data[i];
+	    Identifier *id2 = (Identifier *)tp->idents.data[i];
+
+	    if (!id1->equals(id2))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeInstance::deduceType(Scope *sc,
+	Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+    //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars());
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check
+    if (tparam && tparam->ty == Tinstance)
+    {
+	TypeInstance *tp = (TypeInstance *)tparam;
+
+	//printf("tempinst->tempdecl = %p\n", tempinst->tempdecl);
+	//printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
+	if (!tp->tempinst->tempdecl)
+	{   //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
+	    if (!tp->tempinst->name->equals(tempinst->name))
+	    {
+		/* Handle case of:
+		 *  template Foo(T : sa!(T), alias sa)
+		 */
+		int i = templateIdentifierLookup(tp->tempinst->name, parameters);
+		if (i == -1)
+		{   /* Didn't find it as a parameter identifier. Try looking
+		     * it up and seeing if is an alias. See Bugzilla 1454
+		     */
+		    Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL);
+		    if (s)
+		    {
+			s = s->toAlias();
+			TemplateDeclaration *td = s->isTemplateDeclaration();
+			if (td && td == tempinst->tempdecl)
+			    goto L2;
+		    }
+		    goto Lnomatch;
+		}
+		TemplateParameter *tpx = (TemplateParameter *)parameters->data[i];
+		// This logic duplicates tpx->matchArg()
+		TemplateAliasParameter *ta = tpx->isTemplateAliasParameter();
+		if (!ta)
+		    goto Lnomatch;
+		Dsymbol *sa = tempinst->tempdecl;
+		if (!sa)
+		    goto Lnomatch;
+		if (ta->specAlias && sa != ta->specAlias)
+		    goto Lnomatch;
+		if (dedtypes->data[i])
+		{   // Must match already deduced symbol
+		    Dsymbol *s = (Dsymbol *)dedtypes->data[i];
+
+		    if (s != sa)
+			goto Lnomatch;
+		}
+		dedtypes->data[i] = sa;
+	    }
+	}
+	else if (tempinst->tempdecl != tp->tempinst->tempdecl)
+	    goto Lnomatch;
+
+      L2:
+	if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim)
+	    goto Lnomatch;
+
+	for (int i = 0; i < tempinst->tiargs->dim; i++)
+	{
+	    //printf("\ttest: tempinst->tiargs[%d]\n", i);
+	    int j;
+	    Object *o1 = (Object *)tempinst->tiargs->data[i];
+	    Object *o2 = (Object *)tp->tempinst->tiargs->data[i];
+
+	    Type *t1 = isType(o1);
+	    Type *t2 = isType(o2);
+
+	    Expression *e1 = isExpression(o1);
+	    Expression *e2 = isExpression(o2);
+
+#if 0
+	    if (t1)	printf("t1 = %s\n", t1->toChars());
+	    if (t2)	printf("t2 = %s\n", t2->toChars());
+	    if (e1)	printf("e1 = %s\n", e1->toChars());
+	    if (e2)	printf("e2 = %s\n", e2->toChars());
+#endif
+
+	    if (t1 && t2)
+	    {
+		if (!t1->deduceType(sc, t2, parameters, dedtypes))
+		    goto Lnomatch;
+	    }
+	    else if (e1 && e2)
+	    {
+		if (!e1->equals(e2))
+		{   if (e2->op == TOKvar)
+		    {
+			/*
+			 * (T:Number!(e2), int e2)
+			 */
+			j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
+			goto L1;
+		    }
+		    goto Lnomatch;
+		}
+	    }
+	    else if (e1 && t2 && t2->ty == Tident)
+	    {
+		j = templateParameterLookup(t2, parameters);
+	    L1:
+		if (j == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[j];
+		// BUG: use tp->matchArg() instead of the following
+		TemplateValueParameter *tv = tp->isTemplateValueParameter();
+		if (!tv)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[j];
+		if (e)
+		{
+		    if (!e1->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tv->valType->semantic(0, sc);
+		    MATCH m = (MATCH)e1->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[j] = e1;
+		}
+	    }
+	    // BUG: Need to handle alias and tuple parameters
+	    else
+		goto Lnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeStruct::deduceType()\n");
+    //printf("\tthis->parent   = %s, ", sym->parent->toChars()); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    /* If this struct is a template struct, and we're matching
+     * it against a template instance, convert the struct type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tstruct)
+    {
+	TypeStruct *tp = (TypeStruct *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tenum)
+    {
+	TypeEnum *tp = (TypeEnum *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Ttypedef)
+    {
+	TypeTypedef *tp = (TypeTypedef *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeClass::deduceType(this = %s)\n", toChars());
+
+    /* If this class is a template class, and we're matching
+     * it against a template instance, convert the class type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tclass)
+    {
+	TypeClass *tp = (TypeClass *)tparam;
+
+	//printf("\t%d\n", (MATCH) implicitConvTo(tp));
+	return (MATCH) implicitConvTo(tp);
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+/* ======================== TemplateParameter =============================== */
+
+TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->sparam = NULL;
+}
+
+TemplateTypeParameter  *TemplateParameter::isTemplateTypeParameter()
+{
+    return NULL;
+}
+
+TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
+{
+    return NULL;
+}
+
+TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
+{
+    return NULL;
+}
+
+TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
+{
+    return NULL;
+}
+
+#if DMDV2
+TemplateThisParameter  *TemplateParameter::isTemplateThisParameter()
+{
+    return NULL;
+}
+#endif
+
+/* ======================== TemplateTypeParameter =========================== */
+
+// type-parameter
+
+TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
+	Type *defaultType)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specType = specType;
+    this->defaultType = defaultType;
+}
+
+TemplateTypeParameter  *TemplateTypeParameter::isTemplateTypeParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTypeParameter::syntaxCopy()
+{
+    TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    if (defaultType)
+	tp->defaultType = defaultType->syntaxCopy();
+    return tp;
+}
+
+void TemplateTypeParameter::declareParameter(Scope *sc)
+{
+    //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTypeParameter::semantic(Scope *sc)
+{
+    //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+    if (specType)
+    {
+	specType = specType->semantic(loc, sc);
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultType)
+    {
+	defaultType = defaultType->semantic(loc, sc);
+    }
+#endif
+}
+
+/****************************************
+ * Determine if two TemplateParameters are the same
+ * as far as TemplateDeclaration overloading goes.
+ * Returns:
+ *	1	match
+ *	0	no match
+ */
+
+int TemplateTypeParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+    if (ttp)
+    {
+	if (specType != ttp->specType)
+	    goto Lnomatch;
+
+	if (specType && !specType->equals(ttp->specType))
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ *	i		i'th argument
+ *	tiargs[]	actual arguments to template instance
+ *	parameters[]	template parameters
+ *	dedtypes[]	deduced arguments to template instance
+ *	*psparam	set to symbol declared and initialized to dedtypes[i]
+ */
+
+MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs,
+	int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateTypeParameter::matchArg()\n");
+    Type *t;
+    Object *oarg;
+    MATCH m = MATCHexact;
+    Type *ta;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    ta = isType(oarg);
+    if (!ta)
+	goto Lnomatch;
+    //printf("ta is %s\n", ta->toChars());
+
+    t = (Type *)dedtypes->data[i];
+
+    if (specType)
+    {
+	//printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars());
+	MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes);
+	if (m2 == MATCHnomatch)
+	{   //printf("\tfailed deduceType\n");
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+	t = (Type *)dedtypes->data[i];
+    }
+    else
+    {
+	// So that matches with specializations are better
+	m = MATCHconvert;
+	if (t)
+	{   // Must match already deduced type
+
+	    m = MATCHexact;
+	    if (!t->equals(ta))
+	    {	//printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+		goto Lnomatch;
+	    }
+	}
+    }
+
+    if (!t)
+    {
+	dedtypes->data[i] = ta;
+	t = ta;
+    }
+    *psparam = new AliasDeclaration(loc, ident, t);
+    //printf("\tm = %d\n", m);
+    return m;
+
+Lnomatch:
+    *psparam = NULL;
+    //printf("\tm = %d\n", MATCHnomatch);
+    return MATCHnomatch;
+}
+
+
+void TemplateTypeParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Type *t  = isType(oarg);
+    Type *ta = isType(oded);
+
+    assert(ta);
+
+    if (specType)
+	printf("\tSpecialization: %s\n", specType->toChars());
+    if (defaultType)
+	printf("\tDefault:        %s\n", defaultType->toChars());
+    printf("\tArgument:       %s\n", t ? t->toChars() : "NULL");
+    printf("\tDeduced Type:   %s\n", ta->toChars());
+}
+
+
+void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    if (specType)
+    {
+	buf->writestring(" : ");
+	specType->toCBuffer(buf, NULL, hgs);
+    }
+    if (defaultType)
+    {
+	buf->writestring(" = ");
+	defaultType->toCBuffer(buf, NULL, hgs);
+    }
+}
+
+
+void *TemplateTypeParameter::dummyArg()
+{   Type *t;
+
+    if (specType)
+	t = specType;
+    else
+    {   // Use this for alias-parameter's too (?)
+	t = new TypeIdentifier(loc, ident);
+    }
+    return (void *)t;
+}
+
+
+Object *TemplateTypeParameter::specialization()
+{
+    return specType;
+}
+
+
+Object *TemplateTypeParameter::defaultArg(Scope *sc)
+{
+    Type *t;
+
+    t = defaultType;
+    if (t)
+    {
+	t = t->syntaxCopy();
+	t = t->semantic(loc, sc);
+    }
+    return t;
+}
+
+/* ======================== TemplateThisParameter =========================== */
+
+#if DMDV2
+// this-parameter
+
+TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident,
+	Type *specType,
+	Type *defaultType)
+    : TemplateTypeParameter(loc, ident, specType, defaultType)
+{
+}
+
+TemplateThisParameter  *TemplateThisParameter::isTemplateThisParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateThisParameter::syntaxCopy()
+{
+    TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    if (defaultType)
+	tp->defaultType = defaultType->syntaxCopy();
+    return tp;
+}
+
+void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("this ");
+    TemplateTypeParameter::toCBuffer(buf, hgs);
+}
+#endif
+
+/* ======================== TemplateAliasParameter ========================== */
+
+// alias-parameter
+
+Dsymbol *TemplateAliasParameter::sdummy = NULL;
+
+TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specAliasT = specAliasT;
+    this->defaultAlias = defaultAlias;
+
+    this->specAlias = NULL;
+}
+
+TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateAliasParameter::syntaxCopy()
+{
+    TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias);
+    if (tp->specAliasT)
+	tp->specAliasT = specAliasT->syntaxCopy();
+    if (defaultAlias)
+	tp->defaultAlias = defaultAlias->syntaxCopy();
+    return tp;
+}
+
+void TemplateAliasParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateAliasParameter::semantic(Scope *sc)
+{
+    if (specAliasT)
+    {
+	specAlias = specAliasT->toDsymbol(sc);
+	if (!specAlias)
+	    error(loc, "%s is not a symbol", specAliasT->toChars());
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultAlias)
+	defaultAlias = defaultAlias->semantic(loc, sc);
+#endif
+}
+
+int TemplateAliasParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateAliasParameter *tap = tp->isTemplateAliasParameter();
+
+    if (tap)
+    {
+	if (specAlias != tap->specAlias)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateAliasParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    Dsymbol *sa;
+    Object *oarg;
+    Expression *ea;
+
+    //printf("TemplateAliasParameter::matchArg()\n");
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    sa = getDsymbol(oarg);
+    if (!sa)
+	goto Lnomatch;
+
+    if (specAlias)
+    {
+	if (!sa || sa == sdummy)
+	    goto Lnomatch;
+	if (sa != specAlias)
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced symbol
+	Dsymbol *s = (Dsymbol *)dedtypes->data[i];
+
+	if (!sa || s != sa)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = sa;
+
+    *psparam = new AliasDeclaration(loc, ident, sa);
+    return MATCHexact;
+
+Lnomatch:
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateAliasParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Dsymbol *sa = isDsymbol(oded);
+    assert(sa);
+
+    printf("\tArgument alias: %s\n", sa->toChars());
+}
+
+void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+    buf->writestring(ident->toChars());
+    if (specAliasT)
+    {
+	buf->writestring(" : ");
+	specAliasT->toCBuffer(buf, NULL, hgs);
+    }
+    if (defaultAlias)
+    {
+	buf->writestring(" = ");
+	defaultAlias->toCBuffer(buf, NULL, hgs);
+    }
+}
+
+
+void *TemplateAliasParameter::dummyArg()
+{   Dsymbol *s;
+
+    s = specAlias;
+    if (!s)
+    {
+	if (!sdummy)
+	    sdummy = new Dsymbol();
+	s = sdummy;
+    }
+    return (void*)s;
+}
+
+
+Object *TemplateAliasParameter::specialization()
+{
+    return specAliasT;
+}
+
+
+Object *TemplateAliasParameter::defaultArg(Scope *sc)
+{
+    Dsymbol *s = NULL;
+
+    if (defaultAlias)
+    {
+	s = defaultAlias->toDsymbol(sc);
+	if (!s)
+	    error("%s is not a symbol", defaultAlias->toChars());
+    }
+    return s;
+}
+
+/* ======================== TemplateValueParameter ========================== */
+
+// value-parameter
+
+Expression *TemplateValueParameter::edummy = NULL;
+
+TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
+	Expression *specValue, Expression *defaultValue)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->valType = valType;
+    this->specValue = specValue;
+    this->defaultValue = defaultValue;
+}
+
+TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateValueParameter::syntaxCopy()
+{
+    TemplateValueParameter *tp =
+	new TemplateValueParameter(loc, ident, valType, specValue, defaultValue);
+    tp->valType = valType->syntaxCopy();
+    if (specValue)
+	tp->specValue = specValue->syntaxCopy();
+    if (defaultValue)
+	tp->defaultValue = defaultValue->syntaxCopy();
+    return tp;
+}
+
+void TemplateValueParameter::declareParameter(Scope *sc)
+{
+    VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
+    v->storage_class = STCtemplateparameter;
+    if (!sc->insert(v))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+    sparam = v;
+}
+
+void TemplateValueParameter::semantic(Scope *sc)
+{
+    sparam->semantic(sc);
+    valType = valType->semantic(loc, sc);
+    if (!(valType->isintegral() || valType->isfloating() || valType->isString()) &&
+	valType->ty != Tident)
+	error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars());
+
+    if (specValue)
+    {   Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64 || e->op == TOKfloat64 ||
+	    e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring)
+	    specValue = e;
+	//e->toInteger();
+    }
+
+#if 0	// defer semantic analysis to arg match
+    if (defaultValue)
+    {   Expression *e = defaultValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64)
+	    defaultValue = e;
+	//e->toInteger();
+    }
+#endif
+}
+
+int TemplateValueParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+
+    if (tvp)
+    {
+	if (valType != tvp->valType)
+	    goto Lnomatch;
+
+	if (valType && !valType->equals(tvp->valType))
+	    goto Lnomatch;
+
+	if (specValue != tvp->specValue)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+
+MATCH TemplateValueParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateValueParameter::matchArg()\n");
+
+    Initializer *init;
+    Declaration *sparam;
+    MATCH m = MATCHexact;
+    Expression *ei;
+    Object *oarg;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    ei = isExpression(oarg);
+    Type *vt;
+
+    if (!ei && oarg)
+	goto Lnomatch;
+
+    if (specValue)
+    {
+	if (!ei || ei == edummy)
+	    goto Lnomatch;
+
+	Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+
+	ei = ei->syntaxCopy();
+	ei = ei->semantic(sc);
+	ei = ei->optimize(WANTvalue | WANTinterpret);
+	//printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
+	//printf("e : %s, %s\n", e->toChars(), e->type->toChars());
+	if (!ei->equals(e))
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced value
+	Expression *e = (Expression *)dedtypes->data[i];
+
+	if (!ei || !ei->equals(e))
+	    goto Lnomatch;
+    }
+Lmatch:
+    //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty);
+    vt = valType->semantic(0, sc);
+    //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
+    if (ei->type)
+    {
+	m = (MATCH)ei->implicitConvTo(vt);
+	//printf("m: %d\n", m);
+	if (!m)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = ei;
+
+    init = new ExpInitializer(loc, ei);
+    sparam = new VarDeclaration(loc, vt, ident, init);
+    sparam->storage_class = STCconst;
+    *psparam = sparam;
+    return m;
+
+Lnomatch:
+    //printf("\tno match\n");
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateValueParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Expression *ea = isExpression(oded);
+
+    if (specValue)
+	printf("\tSpecialization: %s\n", specValue->toChars());
+    printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL");
+}
+
+
+void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    valType->toCBuffer(buf, ident, hgs);
+    if (specValue)
+    {
+	buf->writestring(" : ");
+	specValue->toCBuffer(buf, hgs);
+    }
+    if (defaultValue)
+    {
+	buf->writestring(" = ");
+	defaultValue->toCBuffer(buf, hgs);
+    }
+}
+
+
+void *TemplateValueParameter::dummyArg()
+{   Expression *e;
+
+    e = specValue;
+    if (!e)
+    {
+	// Create a dummy value
+	if (!edummy)
+	    edummy = valType->defaultInit();
+	e = edummy;
+    }
+    return (void *)e;
+}
+
+
+Object *TemplateValueParameter::specialization()
+{
+    return specValue;
+}
+
+
+Object *TemplateValueParameter::defaultArg(Scope *sc)
+{
+    Expression *e = defaultValue;
+    if (e)
+    {
+	e = e->syntaxCopy();
+	e = e->semantic(sc);
+#if DMDV2
+	if (e->op == TOKdefault)
+	{   DefaultInitExp *de = (DefaultInitExp *)e;
+	    e = de->resolve(loc, sc);
+	}
+#endif
+    }
+    return e;
+}
+
+/* ======================== TemplateTupleParameter ========================== */
+
+// variadic-parameter
+
+TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+}
+
+TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTupleParameter::syntaxCopy()
+{
+    TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident);
+    return tp;
+}
+
+void TemplateTupleParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTupleParameter::semantic(Scope *sc)
+{
+}
+
+int TemplateTupleParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTupleParameter *tvp = tp->isTemplateTupleParameter();
+
+    if (tvp)
+    {
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateTupleParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters,
+	Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateTupleParameter::matchArg()\n");
+
+    /* The rest of the actual arguments (tiargs[]) form the match
+     * for the variadic parameter.
+     */
+    assert(i + 1 == dedtypes->dim);	// must be the last one
+    Tuple *ovar;
+    if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i]))
+	ovar = isTuple((Object *)tiargs->data[i]);
+    else
+    {
+	ovar = new Tuple();
+	//printf("ovar = %p\n", ovar);
+	if (i < tiargs->dim)
+	{
+	    //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim);
+	    ovar->objects.setDim(tiargs->dim - i);
+	    for (size_t j = 0; j < ovar->objects.dim; j++)
+		ovar->objects.data[j] = tiargs->data[i + j];
+	}
+    }
+    *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
+    dedtypes->data[i] = (void *)ovar;
+    return MATCHexact;
+}
+
+
+void TemplateTupleParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s... [", ident->toChars());
+    Tuple *v = isTuple(oded);
+    assert(v);
+
+    //printf("|%d| ", v->objects.dim);
+    for (int i = 0; i < v->objects.dim; i++)
+    {
+	if (i)
+	    printf(", ");
+
+	Object *o = (Object *)v->objects.data[i];
+
+	Dsymbol *sa = isDsymbol(o);
+	if (sa)
+	    printf("alias: %s", sa->toChars());
+
+	Type *ta = isType(o);
+	if (ta)
+	    printf("type: %s", ta->toChars());
+
+	Expression *ea = isExpression(o);
+	if (ea)
+	    printf("exp: %s", ea->toChars());
+
+	assert(!isTuple(o));		// no nested Tuple arguments
+    }
+
+    printf("]\n");
+}
+
+void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    buf->writestring("...");
+}
+
+
+void *TemplateTupleParameter::dummyArg()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::specialization()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::defaultArg(Scope *sc)
+{
+    return NULL;
+}
+
+/* ======================== TemplateInstance ================================ */
+
+TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null");
+#endif
+    this->loc = loc;
+    this->name = ident;
+    this->tiargs = NULL;
+    this->tempdecl = NULL;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->semantictiargsdone = 0;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 0;
+    this->isnested = NULL;
+    this->errors = 0;
+}
+
+
+TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars());
+#endif
+    this->loc = loc;
+    this->name = td->ident;
+    this->tiargs = tiargs;
+    this->tempdecl = td;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->semantictiargsdone = 1;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 1;
+    this->isnested = NULL;
+    this->errors = 0;
+
+    assert((size_t)tempdecl->scope > 0x10000);
+}
+
+
+Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
+{
+    Objects *a = NULL;
+    if (objs)
+    {	a = new Objects();
+	a->setDim(objs->dim);
+	for (size_t i = 0; i < objs->dim; i++)
+	{
+	    Type *ta = isType((Object *)objs->data[i]);
+	    if (ta)
+		a->data[i] = ta->syntaxCopy();
+	    else
+	    {
+		Expression *ea = isExpression((Object *)objs->data[i]);
+		assert(ea);
+		a->data[i] = ea->syntaxCopy();
+	    }
+	}
+    }
+    return a;
+}
+
+Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
+{
+    TemplateInstance *ti;
+    int i;
+
+    if (s)
+	ti = (TemplateInstance *)s;
+    else
+	ti = new TemplateInstance(loc, name);
+
+    ti->tiargs = arraySyntaxCopy(tiargs);
+
+    ScopeDsymbol::syntaxCopy(ti);
+    return ti;
+}
+
+
+void TemplateInstance::semantic(Scope *sc)
+{
+    if (global.errors)
+    {
+	if (!global.gag)
+	{
+	    /* Trying to soldier on rarely generates useful messages
+	     * at this point.
+	     */
+	    fatal();
+	}
+	return;
+    }
+#if LOG
+    printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+    if (inst)		// if semantic() was already run
+    {
+#if LOG
+	printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst);
+#endif
+	return;
+    }
+
+    if (semanticdone != 0)
+    {
+	error(loc, "recursive template expansion");
+//	inst = this;
+	return;
+    }
+    semanticdone = 1;
+
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+    if (havetempdecl)
+    {
+	assert((size_t)tempdecl->scope > 0x10000);
+	// Deduce tdtypes
+	tdtypes.setDim(tempdecl->parameters->dim);
+	if (!tempdecl->matchWithInstance(this, &tdtypes, 0))
+	{
+	    error("incompatible arguments for template instantiation");
+	    inst = this;
+	    return;
+	}
+    }
+    else
+    {
+	// Run semantic on each argument, place results in tiargs[]
+	semanticTiargs(sc);
+
+	tempdecl = findTemplateDeclaration(sc);
+	if (tempdecl)
+	    tempdecl = findBestMatch(sc);
+	if (!tempdecl || global.errors)
+	{   inst = this;
+	    //printf("error return %p, %d\n", tempdecl, global.errors);
+	    return;		// error recovery
+	}
+    }
+
+    isNested(tiargs);
+
+    /* See if there is an existing TemplateInstantiation that already
+     * implements the typeargs. If so, just refer to that one instead.
+     */
+
+    for (size_t i = 0; i < tempdecl->instances.dim; i++)
+    {
+	TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i];
+#if LOG
+	printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars());
+#endif
+	assert(tdtypes.dim == ti->tdtypes.dim);
+
+	// Nesting must match
+	if (isnested != ti->isnested)
+	    continue;
+#if 0
+	if (isnested && sc->parent != ti->parent)
+	    continue;
+#endif
+	for (size_t j = 0; j < tdtypes.dim; j++)
+	{   Object *o1 = (Object *)tdtypes.data[j];
+	    Object *o2 = (Object *)ti->tdtypes.data[j];
+	    if (!match(o1, o2, tempdecl, sc))
+		goto L1;
+	}
+
+	// It's a match
+	inst = ti;
+	parent = ti->parent;
+#if LOG
+	printf("\tit's a match with instance %p\n", inst);
+#endif
+	return;
+
+     L1:
+	;
+    }
+
+    /* So, we need to implement 'this' instance.
+     */
+#if LOG
+    printf("\timplement template instance '%s'\n", toChars());
+#endif
+    unsigned errorsave = global.errors;
+    inst = this;
+    int tempdecl_instance_idx = tempdecl->instances.dim;
+    tempdecl->instances.push(this);
+    parent = tempdecl->parent;
+    //printf("parent = '%s'\n", parent->kind());
+
+    ident = genIdent();		// need an identifier for name mangling purposes.
+
+#if 1
+    if (isnested)
+	parent = isnested;
+#endif
+    //printf("parent = '%s'\n", parent->kind());
+
+    // Add 'this' to the enclosing scope's members[] so the semantic routines
+    // will get called on the instance members
+#if 1
+    int dosemantic3 = 0;
+    {	Array *a;
+	int i;
+
+	if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin())
+	{
+	    //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
+	    a = sc->scopesym->members;
+	}
+	else
+	{   Module *m = sc->module->importedFrom;
+	    //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars());
+	    a = m->members;
+	    if (m->semanticdone >= 3)
+		dosemantic3 = 1;
+	}
+	for (int i = 0; 1; i++)
+	{
+	    if (i == a->dim)
+	    {
+		a->push(this);
+		break;
+	    }
+	    if (this == (Dsymbol *)a->data[i])	// if already in Array
+		break;
+	}
+    }
+#endif
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+    // Create our own scope for the template parameters
+    Scope *scope = tempdecl->scope;
+    if (!scope)
+    {
+	error("forward reference to template declaration %s\n", tempdecl->toChars());
+	return;
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    argsym = new ScopeDsymbol();
+    argsym->parent = scope->parent;
+    scope = scope->push(argsym);
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members of template instance to template instance symbol table
+//    parent = scope->scopesym;
+    symtab = new DsymbolTable();
+    int memnum = 0;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum);
+#endif
+	memnum |= s->addMember(scope, this, memnum);
+    }
+#if LOG
+    printf("adding members done\n");
+#endif
+
+    /* See if there is only one member of template instance, and that
+     * member has the same name as the template instance.
+     * If so, this template instance becomes an alias for that member.
+     */
+    //printf("members->dim = %d\n", members->dim);
+    if (members->dim)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s) && s)
+	{
+	    //printf("s->kind = '%s'\n", s->kind());
+	    //s->print();
+	    //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars());
+	    if (s->ident && s->ident->equals(tempdecl->ident))
+	    {
+		//printf("setting aliasdecl\n");
+		aliasdecl = new AliasDeclaration(loc, s->ident, s);
+	    }
+	}
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars());
+    sc2->parent = /*isnested ? sc->parent :*/ this;
+
+#if !IN_LLVM    
+#if _WIN32
+  __try
+  {
+#endif
+#endif
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+	//printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars());
+//	if (isnested)
+//	    s->parent = sc->parent;
+	//printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	s->semantic(sc2);
+	//printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	sc2->module->runDeferredSemantic();
+    }
+#if !IN_LLVM    
+#if _WIN32
+  }
+  __except (__ehfilter(GetExceptionInformation()))
+  {
+    global.gag = 0;			// ensure error message gets printed
+    error("recursive expansion");
+    fatal();
+  }
+#endif
+#endif
+
+    /* If any of the instantiation members didn't get semantic() run
+     * on them due to forward references, we cannot run semantic2()
+     * or semantic3() yet.
+     */
+    for (size_t i = 0; i < Module::deferred.dim; i++)
+    {	Dsymbol *sd = (Dsymbol *)Module::deferred.data[i];
+
+	if (sd->parent == this)
+	    goto Laftersemantic;
+    }
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	/* BUG 782: this has problems if the classes this depends on
+	 * are forward referenced. Find a way to defer semantic()
+	 * on this template.
+	 */
+	semantic2(sc2);
+
+    if (sc->func || dosemantic3)
+    {
+	semantic3(sc2);
+    }
+
+  Laftersemantic:
+    sc2->pop();
+
+    scope->pop();
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+	errors = 1;
+	if (global.gag)
+	    tempdecl->instances.remove(tempdecl_instance_idx);
+    }
+
+#if LOG
+    printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+
+void TemplateInstance::semanticTiargs(Scope *sc)
+{
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    if (semantictiargsdone)
+	return;
+    semantictiargsdone = 1;
+    semanticTiargs(loc, sc, tiargs);
+}
+
+void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs)
+{
+    // Run semantic on each argument, place results in tiargs[]
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    if (!tiargs)
+	return;
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+
+	//printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
+	if (ta)
+	{
+	    //printf("type %s\n", ta->toChars());
+	    // It might really be an Expression or an Alias
+	    ta->resolve(loc, sc, &ea, &ta, &sa);
+	    if (ea)
+	    {
+		ea = ea->semantic(sc);
+		ea = ea->optimize(WANTvalue | WANTinterpret);
+		tiargs->data[j] = ea;
+	    }
+	    else if (sa)
+	    {	tiargs->data[j] = sa;
+		TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
+		if (d)
+		{
+		    size_t dim = d->objects->dim;
+		    tiargs->remove(j);
+		    tiargs->insert(j, d->objects);
+		    j--;
+		}
+	    }
+	    else if (ta)
+	    {
+		if (ta->ty == Ttuple)
+		{   // Expand tuple
+		    TypeTuple *tt = (TypeTuple *)ta;
+		    size_t dim = tt->arguments->dim;
+		    tiargs->remove(j);
+		    if (dim)
+		    {	tiargs->reserve(dim);
+			for (size_t i = 0; i < dim; i++)
+			{   Argument *arg = (Argument *)tt->arguments->data[i];
+			    tiargs->insert(j + i, arg->type);
+			}
+		    }
+		    j--;
+		}
+		else
+		    tiargs->data[j] = ta;
+	    }
+	    else
+	    {
+		assert(global.errors);
+		tiargs->data[j] = Type::terror;
+	    }
+	}
+	else if (ea)
+	{
+	    if (!ea)
+	    {	assert(global.errors);
+		ea = new IntegerExp(0);
+	    }
+	    assert(ea);
+	    ea = ea->semantic(sc);
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[j] = ea;
+	    if (ea->op == TOKtype)
+		tiargs->data[j] = ea->type;
+	}
+	else if (sa)
+	{
+	}
+	else
+	{
+	    assert(0);
+	}
+	//printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]);
+    }
+#if 0
+    printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this);
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+
+	printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+    }
+#endif
+}
+
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ */
+
+TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc)
+{
+    //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars());
+    if (!tempdecl)
+    {
+	/* Given:
+	 *    foo!( ... )
+	 * figure out which TemplateDeclaration foo refers to.
+	 */
+	Dsymbol *s;
+	Dsymbol *scopesym;
+	Identifier *id;
+	int i;
+
+	id = name;
+	s = sc->search(loc, id, &scopesym);
+	if (!s)
+	{   error("identifier '%s' is not defined", id->toChars());
+	    return NULL;
+	}
+#if LOG
+	printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind());
+	if (s->parent)
+	    printf("s->parent = '%s'\n", s->parent->toChars());
+#endif
+	withsym = scopesym->isWithScopeSymbol();
+
+	/* We might have found an alias within a template when
+	 * we really want the template.
+	 */
+	TemplateInstance *ti;
+	if (s->parent &&
+	    (ti = s->parent->isTemplateInstance()) != NULL)
+	{
+	    if (
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+		s = tempdecl;
+	    }
+	}
+
+	s = s->toAlias();
+
+	/* It should be a TemplateDeclaration, not some other symbol
+	 */
+	tempdecl = s->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    if (!s->parent && global.errors)
+		return NULL;
+	    if (!s->parent && s->getType())
+	    {	Dsymbol *s2 = s->getType()->toDsymbol(sc);
+		if (!s2)
+		{
+		    error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		    return NULL;
+		}
+		s = s2;
+	    }
+#ifdef DEBUG
+	    //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars());
+#endif
+	    //assert(s->parent);
+	    TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
+	    if (ti &&
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+	    }
+	    else
+	    {
+		error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		return NULL;
+	    }
+	}
+    }
+    else
+	assert(tempdecl->isTemplateDeclaration());
+    return tempdecl;
+}
+
+TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc)
+{
+    /* Since there can be multiple TemplateDeclaration's with the same
+     * name, look for the best match.
+     */
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    MATCH m_best = MATCHnomatch;
+    Objects dedtypes;
+
+#if LOG
+    printf("TemplateInstance::findBestMatch()\n");
+#endif
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	MATCH m;
+
+//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]);
+
+	// If more arguments than parameters,
+	// then this is no match.
+	if (td->parameters->dim < tiargs->dim)
+	{
+	    if (!td->isVariadic())
+		continue;
+	}
+
+	dedtypes.setDim(td->parameters->dim);
+	dedtypes.zero();
+	if (!td->scope)
+	{
+	    error("forward reference to template declaration %s", td->toChars());
+	    return NULL;
+	}
+	m = td->matchWithInstance(this, &dedtypes, 0);
+	//printf("m = %d\n", m);
+	if (!m)			// no match at all
+	    continue;
+
+#if 1
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+#else
+	if (!m_best)
+	    goto Ltd;
+#endif
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	int c1 = td->leastAsSpecialized(td_best);
+	int c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 > c2)
+	    goto Ltd;
+	else if (c1 < c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	td_best = td;
+	m_best = m;
+	tdtypes.setDim(dedtypes.dim);
+	memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *));
+	continue;
+    }
+
+    if (!td_best)
+    {
+	error("%s does not match any template declaration", toChars());
+	return NULL;
+    }
+    if (td_ambig)
+    {
+	error("%s matches more than one template declaration, %s and %s",
+		toChars(), td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best
+     */
+    tempdecl = td_best;
+
+#if 0
+    /* Cast any value arguments to be same type as value parameter
+     */
+    for (size_t i = 0; i < tiargs->dim; i++)
+    {	Object *o = (Object *)tiargs->data[i];
+	Expression *ea = isExpression(o);	// value argument
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	assert(tp);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	if (tvp)
+	{
+	    assert(ea);
+	    ea = ea->castTo(tvp->valType);
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[i] = (Object *)ea;
+	}
+    }
+#endif
+
+#if LOG
+    printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars());
+#endif
+    return tempdecl;
+}
+
+
+/*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ */
+
+int TemplateInstance::isNested(Objects *args)
+{   int nested = 0;
+    //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars());
+
+    /* A nested instance happens when an argument references a local
+     * symbol that is on the stack.
+     */
+    for (size_t i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	if (ea)
+	{
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		goto Lsa;
+	    }
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->isDataseg() &&
+#if DMDV2
+		!(d->storage_class & STCmanifest) &&
+#endif
+		(!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
+		!isTemplateMixin())
+	    {
+		// if module level template
+		if (tempdecl->toParent()->isModule())
+		{   Dsymbol *dparent = d->toParent();
+		    if (!isnested)
+			isnested = dparent;
+		    else if (isnested != dparent)
+		    {
+			/* Select the more deeply nested of the two.
+			 * Error if one is not nested inside the other.
+			 */
+			for (Dsymbol *p = isnested; p; p = p->parent)
+			{
+			    if (p == dparent)
+				goto L1;	// isnested is most nested
+			}
+			for (Dsymbol *p = dparent; 1; p = p->parent)
+			{
+			    if (p == isnested)
+			    {	isnested = dparent;
+				goto L1;	// dparent is most nested
+			    }
+			}
+			error("is nested in both %s and %s", isnested->toChars(), dparent->toChars());
+		    }
+		  L1:
+		    //printf("\tnested inside %s\n", isnested->toChars());
+		    nested |= 1;
+		}
+		else
+		    error("cannot use local '%s' as template parameter", d->toChars());
+	    }
+	}
+	else if (va)
+	{
+	    nested |= isNested(&va->objects);
+	}
+    }
+    return nested;
+}
+
+/****************************************
+ * This instance needs an identifier for name mangling purposes.
+ * Create one by taking the template declaration name and adding
+ * the type signature for it.
+ */
+
+Identifier *TemplateInstance::genIdent()
+{   OutBuffer buf;
+    char *id;
+    Objects *args;
+
+    //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+    id = tempdecl->ident->toChars();
+    buf.printf("__T%"PRIuSIZE"%s", strlen(id), id);
+    args = tiargs;
+    for (int i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	//printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va);
+	if (ta)
+	{
+	    buf.writeByte('T');
+	    if (ta->deco)
+		buf.writestring(ta->deco);
+	    else
+	    {
+#ifdef DEBUG
+		printf("ta = %d, %s\n", ta->ty, ta->toChars());
+#endif
+		assert(global.errors);
+	    }
+	}
+	else if (ea)
+	{   sinteger_t v;
+	    real_t r;
+
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    buf.writeByte('V');
+	    if (ea->op == TOKtuple)
+	    {	ea->error("tuple is not a valid template value argument");
+		continue;
+	    }
+#if 1
+	    /* Use deco that matches what it would be for a function parameter
+	     */
+	    buf.writestring(ea->type->deco);
+#else
+	    // Use type of parameter, not type of argument
+	    TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	    assert(tp);
+	    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	    assert(tvp);
+	    buf.writestring(tvp->valType->deco);
+#endif
+	    ea->toMangleBuffer(&buf);
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    buf.writeByte('S');
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->type->deco)
+		error("forward reference of %s", d->toChars());
+	    else
+	    {
+		char *p = sa->mangle();
+        buf.printf("%"PRIuSIZE"%s", strlen(p), p);
+	    }
+	}
+	else if (va)
+	{
+	    assert(i + 1 == args->dim);		// must be last one
+	    args = &va->objects;
+	    i = -1;
+	}
+	else
+	    assert(0);
+    }
+    buf.writeByte('Z');
+    id = buf.toChars();
+    buf.data = NULL;
+    return new Identifier(id, TOKidentifier);
+}
+
+
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+
+void TemplateInstance::declareParameters(Scope *scope)
+{
+    //printf("TemplateInstance::declareParameters()\n");
+    for (int i = 0; i < tdtypes.dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	//Object *o = (Object *)tiargs->data[i];
+	Object *o = (Object *)tdtypes.data[i];
+
+	//printf("\ttdtypes[%d] = %p\n", i, o);
+	tempdecl->declareParameter(scope, tp, o);
+    }
+}
+
+
+void TemplateInstance::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateInstance::semantic3(Scope *sc)
+{
+#if LOG
+    printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone);
+#endif
+//if (toChars()[0] == 'D') *(char*)0=0;
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateInstance::toObjFile(int multiobj)
+{
+#if LOG
+    printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this);
+#endif
+    if (!errors && members)
+    {
+	if (multiobj)
+	    // Append to list of object files to be written later
+	    //obj_append(this);
+        assert(0 && "multiobj");
+	else
+	{
+	    for (int i = 0; i < members->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)members->data[i];
+		s->toObjFile(multiobj);
+	    }
+	}
+    }
+}
+
+void TemplateInstance::inlineScan()
+{
+#if LOG
+    printf("TemplateInstance::inlineScan('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->inlineScan();
+	}
+    }
+}
+
+void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    int i;
+
+    Identifier *id = name;
+    buf->writestring(id->toChars());
+    buf->writestring("!(");
+    if (nest)
+	buf->writestring("...");
+    else
+    {
+	nest++;
+	Objects *args = tiargs;
+	for (i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *oarg = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, oarg);
+	}
+	nest--;
+    }
+    buf->writeByte(')');
+}
+
+
+Dsymbol *TemplateInstance::toAlias()
+{
+#if LOG
+    printf("TemplateInstance::toAlias()\n");
+#endif
+    if (!inst)
+    {	error("cannot resolve forward reference");
+	return this;
+    }
+
+    if (inst != this)
+	return inst->toAlias();
+
+    if (aliasdecl)
+	return aliasdecl->toAlias();
+
+    return inst;
+}
+
+AliasDeclaration *TemplateInstance::isAliasDeclaration()
+{
+    return aliasdecl;
+}
+
+const char *TemplateInstance::kind()
+{
+    return "template instance";
+}
+
+int TemplateInstance::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+char *TemplateInstance::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+/* ======================== TemplateMixin ================================ */
+
+TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual,
+	Array *idents, Objects *tiargs)
+	: TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1])
+{
+    //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
+    this->ident = ident;
+    this->tqual = tqual;
+    this->idents = idents;
+    this->tiargs = tiargs ? tiargs : new Objects();
+    this->scope = NULL;
+}
+
+Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s)
+{   TemplateMixin *tm;
+
+    Array *ids = new Array();
+    ids->setDim(idents->dim);
+    for (int i = 0; i < idents->dim; i++)
+    {	// Matches TypeQualified::syntaxCopyHelper()
+        Identifier *id = (Identifier *)idents->data[i];
+        if (id->dyncast() == DYNCAST_DSYMBOL)
+        {
+            TemplateInstance *ti = (TemplateInstance *)id;
+
+            ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+            id = (Identifier *)ti;
+        }
+        ids->data[i] = id;
+    }
+
+    tm = new TemplateMixin(loc, ident,
+		(Type *)(tqual ? tqual->syntaxCopy() : NULL),
+		ids, tiargs);
+    TemplateInstance::syntaxCopy(tm);
+    return tm;
+}
+
+void TemplateMixin::semantic(Scope *sc)
+{
+#if LOG
+    printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+    fflush(stdout);
+#endif
+    if (semanticdone &&
+	// This for when a class/struct contains mixin members, and
+	// is done over because of forward references
+	(!parent || !toParent()->isAggregateDeclaration()))
+    {
+#if LOG
+	printf("\tsemantic done\n");
+#endif
+	return;
+    }
+    if (!semanticdone)
+	semanticdone = 1;
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+
+#if !IN_LLVM
+    // dont know what this is
+    util_progress();
+#endif
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    // Follow qualifications to find the TemplateDeclaration
+    if (!tempdecl)
+    {	Dsymbol *s;
+	int i;
+	Identifier *id;
+
+	if (tqual)
+	{   s = tqual->toDsymbol(sc);
+	    i = 0;
+	}
+	else
+	{
+	    i = 1;
+	    id = (Identifier *)idents->data[0];
+	    switch (id->dyncast())
+	    {
+		case DYNCAST_IDENTIFIER:
+		    s = sc->search(loc, id, NULL);
+		    break;
+
+		case DYNCAST_DSYMBOL:
+		{
+		    TemplateInstance *ti = (TemplateInstance *)id;
+		    ti->semantic(sc);
+		    s = ti;
+		    break;
+		}
+		default:
+		    assert(0);
+	    }
+	}
+
+	for (; i < idents->dim; i++)
+	{
+	    if (!s)
+		break;
+	    id = (Identifier *)idents->data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (!s)
+	{
+	    error("is not defined");
+	    inst = this;
+	    return;
+	}
+	tempdecl = s->toAlias()->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    error("%s isn't a template", s->toChars());
+	    inst = this;
+	    return;
+	}
+    }
+
+    // Look for forward reference
+    assert(tempdecl);
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    /* Cannot handle forward references if mixin is a struct member,
+	     * because addField must happen during struct's semantic, not
+	     * during the mixin semantic.
+	     * runDeferred will re-run mixin's semantic outside of the struct's
+	     * semantic.
+	     */
+	    semanticdone = 0;
+	    AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
+	    if (ad)
+		ad->sizeok = 2;
+	    else
+	    {
+		// Forward reference
+		//printf("forward reference - deferring\n");
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    return;
+	}
+    }
+
+    // Run semantic on each argument, place results in tiargs[]
+    semanticTiargs(sc);
+
+    tempdecl = findBestMatch(sc);
+    if (!tempdecl)
+    {	inst = this;
+	return;		// error recovery
+    }
+
+    if (!ident)
+	ident = genIdent();
+
+    inst = this;
+    parent = sc->parent;
+
+    /* Detect recursive mixin instantiations.
+     */
+    for (Dsymbol *s = parent; s; s = s->parent)
+    {
+	//printf("\ts = '%s'\n", s->toChars());
+	TemplateMixin *tm = s->isTemplateMixin();
+	if (!tm || tempdecl != tm->tempdecl)
+	    continue;
+
+	/* Different argument list lengths happen with variadic args
+	 */
+	if (tiargs->dim != tm->tiargs->dim)
+	    continue;
+
+	for (int i = 0; i < tiargs->dim; i++)
+	{   Object *o = (Object *)tiargs->data[i];
+	    Type *ta = isType(o);
+	    Expression *ea = isExpression(o);
+	    Dsymbol *sa = isDsymbol(o);
+	    Object *tmo = (Object *)tm->tiargs->data[i];
+	    if (ta)
+	    {
+		Type *tmta = isType(tmo);
+		if (!tmta)
+		    goto Lcontinue;
+		if (!ta->equals(tmta))
+		    goto Lcontinue;
+	    }
+	    else if (ea)
+	    {	Expression *tme = isExpression(tmo);
+		if (!tme || !ea->equals(tme))
+		    goto Lcontinue;
+	    }
+	    else if (sa)
+	    {
+		Dsymbol *tmsa = isDsymbol(tmo);
+		if (sa != tmsa)
+		    goto Lcontinue;
+	    }
+	    else
+		assert(0);
+	}
+	error("recursive mixin instantiation");
+	return;
+
+    Lcontinue:
+	continue;
+    }
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+    if (!members)
+	return;
+
+    symtab = new DsymbolTable();
+
+    for (Scope *sce = sc; 1; sce = sce->enclosing)
+    {
+	ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
+	if (sds)
+	{
+	    sds->importScope(this, PROTpublic);
+	    break;
+	}
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    Scope *scy = sc;
+    scy = sc->push(this);
+    scy->parent = this;
+
+    argsym = new ScopeDsymbol();
+    argsym->parent = scy->parent;
+    Scope *scope = scy->push(argsym);
+
+    unsigned errorsave = global.errors;
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members to enclosing scope, as well as this scope
+    for (unsigned i = 0; i < members->dim; i++)
+    {   Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->addMember(scope, this, i);
+	//sc->insert(s);
+	//printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
+	//printf("s->parent = %s\n", s->parent->toChars());
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    sc2->offset = sc->offset;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc2);
+    }
+    sc->offset = sc2->offset;
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	semantic2(sc2);
+
+    if (sc->func)
+    {
+	semantic3(sc2);
+    }
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+    }
+
+    sc2->pop();
+
+    scope->pop();
+
+//    if (!isAnonymous())
+    {
+	scy->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+void TemplateMixin::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	    printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateMixin::semantic3(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+#if LOG
+    printf("TemplateMixin::semantic3('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateMixin::inlineScan()
+{
+    TemplateInstance::inlineScan();
+}
+
+const char *TemplateMixin::kind()
+{
+    return "mixin";
+}
+
+int TemplateMixin::oneMember(Dsymbol **ps)
+{
+    return Dsymbol::oneMember(ps);
+}
+
+int TemplateMixin::hasPointers()
+{
+    //printf("TemplateMixin::hasPointers() %s\n", toChars());
+    for (size_t i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf(" s = %s %s\n", s->kind(), s->toChars());
+	if (s->hasPointers())
+	{
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+char *TemplateMixin::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    TemplateInstance::toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin ");
+
+    for (int i = 0; i < idents->dim; i++)
+    {   Identifier *id = (Identifier *)idents->data[i];
+
+    	if (i)
+	    buf->writeByte('.');
+	buf->writestring(id->toChars());
+    }
+    buf->writestring("!(");
+    if (tiargs)
+    {
+        for (int i = 0; i < tiargs->dim; i++)
+        {   if (i)
+                buf->writebyte(',');
+	    Object *oarg = (Object *)tiargs->data[i];
+	    Type *t = isType(oarg);
+	    Expression *e = isExpression(oarg);
+	    Dsymbol *s = isDsymbol(oarg);
+	    if (t)
+		t->toCBuffer(buf, NULL, hgs);
+	    else if (e)
+		e->toCBuffer(buf, hgs);
+	    else if (s)
+	    {
+		char *p = s->ident ? s->ident->toChars() : s->toChars();
+		buf->writestring(p);
+	    }
+	    else if (!oarg)
+	    {
+		buf->writestring("NULL");
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+        }
+    }
+    buf->writebyte(')');
+    if (ident)
+    {
+	buf->writebyte(' ');
+	buf->writestring(ident->toChars());
+    }
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+
+void TemplateMixin::toObjFile(int multiobj)
+{
+    //printf("TemplateMixin::toObjFile('%s')\n", toChars());
+    TemplateInstance::toObjFile(multiobj);
+}
+
--- a/dmd/template.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/template.h	Sat Jul 12 19:38:31 2008 +0200
@@ -26,6 +26,7 @@
 struct TemplateInstance;
 struct TemplateParameter;
 struct TemplateTypeParameter;
+struct TemplateThisParameter;
 struct TemplateValueParameter;
 struct TemplateAliasParameter;
 struct TemplateTupleParameter;
@@ -52,7 +53,7 @@
 
     TemplateParameters *origParameters;	// originals for Ddoc
 
-    Array instances;		// array of TemplateInstance's
+    Array instances;			// array of TemplateInstance's
 
     TemplateDeclaration *overnext;	// next overloaded TemplateDeclaration
     TemplateDeclaration *overroot;	// first in overnext list
@@ -65,7 +66,7 @@
     void semantic(Scope *sc);
     int overloadInsert(Dsymbol *s);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
     char *toChars();
 
     void emitComment(Scope *sc);
@@ -152,6 +153,23 @@
     void *dummyArg();
 };
 
+#if DMDV2
+struct TemplateThisParameter : TemplateTypeParameter
+{
+    /* Syntax:
+     *	this ident : specType = defaultType
+     */
+    Type *specType;	// type parameter: if !=NULL, this is the type specialization
+    Type *defaultType;
+
+    TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+    TemplateThisParameter *isTemplateThisParameter();
+    TemplateParameter *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+#endif
+
 struct TemplateValueParameter : TemplateParameter
 {
     /* Syntax:
@@ -251,6 +269,7 @@
 					// sole member
     WithScopeSymbol *withsym;		// if a member of a with statement
     int semanticdone;	// has semantic() been done?
+    int semantictiargsdone;	// has semanticTiargs() been done?
     int nest;		// for recursion detection
     int havetempdecl;	// 1 if used second constructor
     Dsymbol *isnested;	// if referencing local symbols, this is the context
@@ -272,12 +291,12 @@
     void inlineScan();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Dsymbol *toAlias();			// resolve real symbol
-    char *kind();
+    const char *kind();
     int oneMember(Dsymbol **ps);
     char *toChars();
     char *mangle();
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
 
     // Internal
     static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs);
@@ -305,14 +324,14 @@
     void semantic2(Scope *sc);
     void semantic3(Scope *sc);
     void inlineScan();
-    char *kind();
+    const char *kind();
     int oneMember(Dsymbol **ps);
     int hasPointers();
     char *toChars();
     char *mangle();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
-    void toObjFile();			// compile to .obj file
+    void toObjFile(int multiobj);			// compile to .obj file
 
     TemplateMixin *isTemplateMixin() { return this; }
 };
--- a/dmd/version.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/version.c	Sat Jul 12 19:38:31 2008 +0200
@@ -93,7 +93,7 @@
     buf->writenl();
 }
 
-char *DebugSymbol::kind()
+const char *DebugSymbol::kind()
 {
     return "debug";
 }
@@ -173,7 +173,7 @@
     buf->writenl();
 }
 
-char *VersionSymbol::kind()
+const char *VersionSymbol::kind()
 {
     return "version";
 }
--- a/dmd/version.h	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/version.h	Sat Jul 12 19:38:31 2008 +0200
@@ -31,7 +31,7 @@
     int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
 };
 
 struct VersionSymbol : Dsymbol
@@ -45,7 +45,7 @@
     int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    char *kind();
+    const char *kind();
 };
 
 #endif /* DMD_VERSION_H */
--- a/gen/asmstmt.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/asmstmt.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -165,6 +165,12 @@
     return this;
 }
 
+int AsmStatement::blockExit()
+{
+    //printf("AsmStatement::blockExit(%p)\n", this);
+    return BEfallthru | BEreturn | BEgoto | BEhalt;
+}
+
 void
 AsmStatement::toIR(IRState * irs)
 {
--- a/gen/classes.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/classes.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -80,7 +80,7 @@
 
         for (int k=0; k < arr->dim; k++) {
             VarDeclaration* v = (VarDeclaration*)(arr->data[k]);
-            v->toObjFile();
+            v->toObjFile(0); // TODO: multiobj
         }
     }
 }
@@ -147,7 +147,7 @@
     if(cd->members) {
         for (int k=0; k < cd->members->dim; k++) {
             Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]);
-            dsym->toObjFile();
+            dsym->toObjFile(0); // TODO: multiobj
         }
     }
 
--- a/gen/dvalue.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/dvalue.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -1,12 +1,12 @@
 #include "gen/llvm.h"
 
-#include "declaration.h"
-
 #include "gen/tollvm.h"
 #include "gen/irstate.h"
 #include "gen/logger.h"
 #include "gen/dvalue.h"
 
+#include "declaration.h"
+
 /////////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////////////
 
--- a/gen/functions.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/functions.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -86,7 +86,7 @@
 
     if (typesafeVararg) {
         ClassDeclaration* ti = Type::typeinfo;
-        ti->toObjFile();
+        ti->toObjFile(0); // TODO: multiobj
         DtoForceConstInitDsymbol(ti);
         assert(ti->ir.irStruct->constInit);
         std::vector<const LLType*> types;
--- a/gen/structs.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/structs.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -131,7 +131,7 @@
     Array* arr = &sd->fields;
     for (int k=0; k < arr->dim; k++) {
         VarDeclaration* v = (VarDeclaration*)arr->data[k];
-        v->toObjFile();
+        v->toObjFile(0); // TODO: multiobj
     }
 
     bool thisModule = false;
@@ -144,11 +144,11 @@
         Dsymbol* s = (Dsymbol*)arr->data[k];
         if (FuncDeclaration* fd = s->isFuncDeclaration()) {
             if (thisModule || (fd->prot() != PROTprivate)) {
-                fd->toObjFile();
+                fd->toObjFile(0); // TODO: multiobj
             }
         }
         else if (s->isAttribDeclaration()) {
-            s->toObjFile();
+            s->toObjFile(0); // TODO: multiobj
         }
         else {
             Logger::println("Ignoring dsymbol '%s' in this->members of kind '%s'", s->toPrettyChars(), s->kind());
--- a/gen/toir.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/toir.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -52,7 +52,7 @@
         // static
         if (vd->isDataseg())
         {
-            vd->toObjFile(); // TODO
+            vd->toObjFile(0); // TODO: multiobj
         }
         else
         {
@@ -245,7 +245,7 @@
         else {
             // take care of forward references of global variables
             if (vd->isDataseg() || (vd->storage_class & STCextern)) {
-                vd->toObjFile();
+                vd->toObjFile(0); // TODO: multiobj
                 DtoConstInitGlobal(vd);
             }
             if (!vd->ir.getIrValue() || DtoType(vd->type)->isAbstract()) {
--- a/gen/toobj.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/toobj.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -53,7 +53,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-void Module::genobjfile()
+void Module::genobjfile(int multiobj)
 {
     Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n';
     LOG_SCOPE;
@@ -120,7 +120,7 @@
     for (int k=0; k < members->dim; k++) {
         Dsymbol* dsym = (Dsymbol*)(members->data[k]);
         assert(dsym);
-        dsym->toObjFile();
+        dsym->toObjFile(multiobj);
     }
 
     // main driver loop
@@ -550,7 +550,7 @@
 
 /* ================================================================== */
 
-void Dsymbol::toObjFile()
+void Dsymbol::toObjFile(int multiobj)
 {
     Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars());
 }
@@ -564,7 +564,7 @@
 
 /* ================================================================== */
 
-void InterfaceDeclaration::toObjFile()
+void InterfaceDeclaration::toObjFile(int multiobj)
 {
     //Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars());
     gIR->resolveList.push_back(this);
@@ -572,14 +572,14 @@
 
 /* ================================================================== */
 
-void StructDeclaration::toObjFile()
+void StructDeclaration::toObjFile(int multiobj)
 {
     gIR->resolveList.push_back(this);
 }
 
 /* ================================================================== */
 
-void ClassDeclaration::toObjFile()
+void ClassDeclaration::toObjFile(int multiobj)
 {
     gIR->resolveList.push_back(this);
 }
@@ -596,7 +596,7 @@
 
 /* ================================================================== */
 
-void VarDeclaration::toObjFile()
+void VarDeclaration::toObjFile(int multiobj)
 {
     Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
@@ -604,7 +604,7 @@
     if (aliassym)
     {
         Logger::println("alias sym");
-        toAlias()->toObjFile();
+        toAlias()->toObjFile(multiobj);
         return;
     }
 
@@ -669,7 +669,7 @@
 
 /* ================================================================== */
 
-void TypedefDeclaration::toObjFile()
+void TypedefDeclaration::toObjFile(int multiobj)
 {
     static int tdi = 0;
     Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars());
@@ -681,14 +681,14 @@
 
 /* ================================================================== */
 
-void EnumDeclaration::toObjFile()
+void EnumDeclaration::toObjFile(int multiobj)
 {
     Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars());
 }
 
 /* ================================================================== */
 
-void FuncDeclaration::toObjFile()
+void FuncDeclaration::toObjFile(int multiobj)
 {
     gIR->resolveList.push_back(this);
 }
--- a/gen/typinf.cpp	Sat Jul 12 17:04:36 2008 +0200
+++ b/gen/typinf.cpp	Sat Jul 12 19:38:31 2008 +0200
@@ -123,7 +123,7 @@
         }
         else            // if in obj generation pass
         {
-        t->vtinfo->toObjFile();
+        t->vtinfo->toObjFile(0); // TODO: multiobj
         }
     }
     }
@@ -244,7 +244,7 @@
 //                             MAGIC   PLACE
 //////////////////////////////////////////////////////////////////////////////
 
-void TypeInfoDeclaration::toObjFile()
+void TypeInfoDeclaration::toObjFile(int multiobj)
 {
     gIR->resolveList.push_back(this);
 }
--- a/premake.lua	Sat Jul 12 17:04:36 2008 +0200
+++ b/premake.lua	Sat Jul 12 19:38:31 2008 +0200
@@ -18,6 +18,9 @@
     end
 end
 
+-- D version - don't change these !!!
+DMDV1 = "1"
+
 -- idgen
 package = newpackage()
 package.name = "idgen"
@@ -26,6 +29,7 @@
 package.files = { "dmd/idgen.c" }
 package.buildoptions = { "-x c++" }
 package.postbuildcommands = { "./idgen", "mv -f id.c id.h dmd" }
+package.defines = { "DMDV1="..DMDV1 }
 
 -- impcnvgen
 package = newpackage()
@@ -35,6 +39,14 @@
 package.files = { "dmd/impcnvgen.c" }
 package.buildoptions = { "-x c++" }
 package.postbuildcommands = { "./impcnvgen", "mv -f impcnvtab.c dmd" }
+package.defines = { "DMDV1="..DMDV1 }
+
+--md5
+package = newpackage()
+package.name = "md5"
+package.kind = "lib"
+package.language = "c"
+package.files = { "dmd/md5.c" }
 
 -- llvmdc
 package = newpackage()
@@ -43,7 +55,7 @@
 package.kind = "exe"
 package.language = "c++"
 package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.cpp"), matchfiles("ir/*.cpp") }
-package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" }
+package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c", "dmd/md5.c" }
 package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" }
 package.linkoptions = {
     -- long but it's faster than just 'all'
@@ -55,6 +67,7 @@
     "_DH",
     "OPAQUE_VTBLS="..OPAQUE_VTBLS,
     "USE_BOEHM_GC="..USE_BOEHM_GC,
+    "DMDV1="..DMDV1,
 }
 package.config.Release.defines = { "LLVMD_NO_LOGGER" }
 package.config.Debug.buildoptions = { "-g -O0" }