changeset 1452:638d16625da2

LDC 2 compiles again.
author Robert Clipsham <robert@octarineparrot.com>
date Sat, 30 May 2009 17:23:32 +0100
parents 42bd767ec5a4
children f35a9a77d256
files dmd2/access.c dmd2/aggregate.h dmd2/aliasthis.c dmd2/aliasthis.h dmd2/arrayop.c dmd2/attrib.c dmd2/attrib.h dmd2/backendlicense.txt dmd2/builtin.c dmd2/cast.c dmd2/class.c dmd2/clone.c dmd2/cond.c dmd2/constfold.c dmd2/cppmangle.c dmd2/declaration.c dmd2/declaration.h dmd2/doc.c dmd2/dsymbol.c dmd2/dsymbol.h dmd2/dump.c dmd2/entity.c dmd2/enum.c dmd2/enum.h dmd2/expression.c dmd2/expression.h dmd2/func.c dmd2/hdrgen.c dmd2/html.c dmd2/html.h dmd2/id.c dmd2/id.h dmd2/identifier.c dmd2/identifier.h dmd2/idgen dmd2/idgen.c dmd2/impcnvgen dmd2/impcnvtab.c dmd2/import.c dmd2/inifile.c dmd2/init.c dmd2/init.h dmd2/inline.c dmd2/interpret.c dmd2/irstate.c dmd2/irstate.h dmd2/lexer.c dmd2/lexer.h dmd2/lib.h dmd2/macro.c dmd2/mangle.c dmd2/mars.c dmd2/mars.h dmd2/mem.c dmd2/module.c dmd2/module.h dmd2/mtype.c dmd2/mtype.h dmd2/objfile.h dmd2/opover.c dmd2/optimize.c dmd2/parse.c dmd2/parse.h dmd2/readme.txt dmd2/root/array.c dmd2/root/async.c dmd2/root/async.h dmd2/root/dchar.c dmd2/root/dchar.h dmd2/root/gnuc.c dmd2/root/gnuc.h dmd2/root/lstring.c dmd2/root/lstring.h dmd2/root/man.c dmd2/root/port.c dmd2/root/port.h dmd2/root/response.c dmd2/root/rmem.c dmd2/root/rmem.h dmd2/root/root.c dmd2/root/root.h dmd2/root/stringtable.c dmd2/root/stringtable.h dmd2/scope.c dmd2/scope.h dmd2/statement.c dmd2/statement.h dmd2/staticassert.c dmd2/struct.c dmd2/template.c dmd2/template.h dmd2/total.h dmd2/traits.c gen/llvmhelpers.cpp gen/typinf.cpp ir/irclass.cpp ir/irtypeclass.cpp
diffstat 97 files changed, 67415 insertions(+), 57031 deletions(-) [+]
line wrap: on
line diff
--- a/dmd2/access.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/access.c	Sat May 30 17:23:32 2009 +0100
@@ -1,424 +1,425 @@
-
-// 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);
-    }
-}
+
+// 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 "rmem.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->getModule() != sc->module)
+	    if (d->prot() == PROTprivate ||
+		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/dmd2/aggregate.h	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/aggregate.h	Sat May 30 17:23:32 2009 +0100
@@ -1,292 +1,320 @@
-
-// 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_AGGREGATE_H
-#define DMD_AGGREGATE_H
-
-#ifdef __DMC__
-#pragma once
-#endif /* __DMC__ */
-
-#include "root.h"
-#include "dsymbol.h"
-
-#include <vector>
-#include <set>
-#include <map>
-
-struct Identifier;
-struct Type;
-struct TypeFunction;
-struct Expression;
-struct FuncDeclaration;
-struct CtorDeclaration;
-struct DtorDeclaration;
-struct InvariantDeclaration;
-struct NewDeclaration;
-struct DeleteDeclaration;
-struct InterfaceDeclaration;
-struct ClassInfoDeclaration;
-struct VarDeclaration;
-struct dt_t;
-
-namespace llvm
-{
-    class Type;
-    class Value;
-    class Constant;
-    class ConstantStruct;
-    class GlobalVariable;
-}
-
-struct AggregateDeclaration : ScopeDsymbol
-{
-    Type *type;
-    unsigned storage_class;
-    enum PROT protection;
-    Type *handle;		// 'this' type
-    unsigned structsize;	// size of struct
-    unsigned alignsize;		// size of struct for alignment purposes
-    unsigned structalign;	// struct member alignment in effect
-    int hasUnions;		// set if aggregate has overlapping fields
-    Array fields;		// VarDeclaration fields
-    unsigned sizeok;		// set when structsize contains valid data
-				// 0: no size
-				// 1: size is correct
-				// 2: cannot determine size; fwd referenced
-    int isdeprecated;		// !=0 if deprecated
-    Scope *scope;		// !=NULL means context to use
-
-    // Special member functions
-    InvariantDeclaration *inv;		// invariant
-    NewDeclaration *aggNew;		// allocator
-    DeleteDeclaration *aggDelete;	// deallocator
-
-#if DMDV2
-    CtorDeclaration *ctor;
-    CtorDeclaration *defaultCtor;	// default constructor
-#endif
-
-    FuncDeclarations dtors;	// Array of destructors
-    FuncDeclaration *dtor;	// aggregate destructor
-
-#ifdef IN_GCC
-    Array methods;              // flat list of all methods for debug information
-#endif
-
-    AggregateDeclaration(Loc loc, Identifier *id);
-    void semantic2(Scope *sc);
-    void semantic3(Scope *sc);
-    void inlineScan();
-    unsigned size(Loc loc);
-    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
-    Type *getType();
-    void addField(Scope *sc, VarDeclaration *v);
-    int isDeprecated();		// is aggregate deprecated?
-    FuncDeclaration *buildDtor(Scope *sc);
-
-    void emitComment(Scope *sc);
-    void toDocBuffer(OutBuffer *buf);
-
-    // For access checking
-    virtual PROT getAccess(Dsymbol *smember);	// determine access to smember
-    int isFriendOf(AggregateDeclaration *cd);
-    int hasPrivateAccess(Dsymbol *smember);	// does smember have private access to members of this class?
-    void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
-
-    enum PROT prot();
-
-    // Back end
-    Symbol *stag;		// tag symbol for debug data
-    Symbol *sinit;
-    Symbol *toInitializer();
-
-    AggregateDeclaration *isAggregateDeclaration() { return this; }
-};
-
-struct AnonymousAggregateDeclaration : AggregateDeclaration
-{
-    AnonymousAggregateDeclaration()
-	: AggregateDeclaration(0, NULL)
-    {
-    }
-
-    AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
-};
-
-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();
-    const char *kind();
-    int needOpAssign();
-    FuncDeclaration *buildOpAssign(Scope *sc);
-    FuncDeclaration *buildPostBlit(Scope *sc);
-    FuncDeclaration *buildCpCtor(Scope *sc);
-    void toDocBuffer(OutBuffer *buf);
-
-    PROT getAccess(Dsymbol *smember);	// determine access to smember
-
-    void toObjFile(int multiobj);			// compile to .obj file
-    void toDt(dt_t **pdt);
-    void toDebug();			// to symbolic debug info
-
-    StructDeclaration *isStructDeclaration() { return this; }
-};
-
-struct UnionDeclaration : StructDeclaration
-{
-    UnionDeclaration(Loc loc, Identifier *id);
-    Dsymbol *syntaxCopy(Dsymbol *s);
-    const char *kind();
-
-    UnionDeclaration *isUnionDeclaration() { return this; }
-};
-
-struct BaseClass
-{
-    Type *type;				// (before semantic processing)
-    enum PROT protection;		// protection for the base interface
-
-    ClassDeclaration *base;
-    int offset;				// 'this' pointer offset
-    Array vtbl;				// for interfaces: Array of FuncDeclaration's
-					// making up the vtbl[]
-
-    int baseInterfaces_dim;
-    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
-					// are a copy of the InterfaceDeclaration::interfaces
-
-    BaseClass();
-    BaseClass(Type *type, enum PROT protection);
-
-    int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance);
-    void copyBaseInterfaces(BaseClasses *);
-};
-
-#if DMDV2
-#define CLASSINFO_SIZE 	(0x3C+16)	// value of ClassInfo.size
-#else
-#define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
-#endif
-
-struct ClassDeclaration : AggregateDeclaration
-{
-    static ClassDeclaration *object;
-    static ClassDeclaration *classinfo;
-
-    ClassDeclaration *baseClass;	// NULL only if this is Object
-    FuncDeclaration *staticCtor;
-    FuncDeclaration *staticDtor;
-    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
-    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]
-
-    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
-					// rest are Interface's
-
-    int interfaces_dim;
-    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
-					// (does not include baseClass)
-
-    BaseClasses *vtblInterfaces;	// array of base interfaces that have
-					// their own vtbl[]
-
-    ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this ClassDeclaration
-    int com;				// !=0 if this is a COM class (meaning
-					// it derives from IUnknown)
-    int isauto;				// !=0 if this is an auto class
-    int isabstract;			// !=0 if abstract class
-
-    int isnested;			// !=0 if is nested
-    VarDeclaration *vthis;		// 'this' parameter if this class is nested
-
-    int inuse;				// to prevent recursive attempts
-
-    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
-    Dsymbol *syntaxCopy(Dsymbol *s);
-    void semantic(Scope *sc);
-    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
-    int isBaseOf2(ClassDeclaration *cd);
-
-    #define OFFSET_RUNTIME 0x76543210
-    virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
-
-    Dsymbol *search(Loc, Identifier *ident, int flags);
-#if DMDV2
-    int isFuncHidden(FuncDeclaration *fd);
-#endif
-    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
-    void interfaceSemantic(Scope *sc);
-    int isNested();
-    int isCOMclass();
-    virtual int isCOMinterface();
-#if DMDV2
-    virtual int isCPPinterface();
-#endif
-    int isAbstract();
-    virtual int vtblOffset();
-    const char *kind();
-    char *mangle();
-    void toDocBuffer(OutBuffer *buf);
-
-    PROT getAccess(Dsymbol *smember);	// determine access to smember
-
-    void addLocalClass(ClassDeclarations *);
-
-    // Back end
-    void toObjFile(int multiobj);			// compile to .obj file
-    void toDebug();
-    unsigned baseVtblOffset(BaseClass *bc);
-    Symbol *toSymbol();
-    Symbol *toVtblSymbol();
-    void toDt(dt_t **pdt);
-    void toDt2(dt_t **pdt, ClassDeclaration *cd);
-
-    Symbol *vtblsym;
-
-    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
-};
-
-struct InterfaceDeclaration : ClassDeclaration
-{
-#if DMDV2
-    int cpp;				// !=0 if this is a C++ interface
-#endif
-    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
-    Dsymbol *syntaxCopy(Dsymbol *s);
-    void semantic(Scope *sc);
-    int isBaseOf(ClassDeclaration *cd, int *poffset);
-    int isBaseOf(BaseClass *bc, int *poffset);
-    const char *kind();
-    int vtblOffset();
-#if DMDV2
-    int isCPPinterface();
-#endif
-    virtual int isCOMinterface();
-
-    void toObjFile(int multiobj);			// compile to .obj file
-    Symbol *toSymbol();
-
-    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
-};
-
-#endif /* DMD_AGGREGATE_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_AGGREGATE_H
+#define DMD_AGGREGATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+#if IN_LLVM
+#include <vector>
+#include <set>
+#include <map>
+#endif
+
+struct Identifier;
+struct Type;
+struct TypeFunction;
+struct Expression;
+struct FuncDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct InvariantDeclaration;
+struct NewDeclaration;
+struct DeleteDeclaration;
+struct InterfaceDeclaration;
+struct ClassInfoDeclaration;
+struct VarDeclaration;
+struct dt_t;
+
+#if IN_LLVM
+namespace llvm
+{
+    class Type;
+    class Value;
+    class Constant;
+    class ConstantStruct;
+    class GlobalVariable;
+}
+#endif
+
+struct AggregateDeclaration : ScopeDsymbol
+{
+    Type *type;
+    unsigned storage_class;
+    enum PROT protection;
+    Type *handle;		// 'this' type
+    unsigned structsize;	// size of struct
+    unsigned alignsize;		// size of struct for alignment purposes
+    unsigned structalign;	// struct member alignment in effect
+    int hasUnions;		// set if aggregate has overlapping fields
+    Array fields;		// VarDeclaration fields
+    unsigned sizeok;		// set when structsize contains valid data
+				// 0: no size
+				// 1: size is correct
+				// 2: cannot determine size; fwd referenced
+    int isdeprecated;		// !=0 if deprecated
+    Scope *scope;		// !=NULL means context to use
+
+    int isnested;		// !=0 if is nested
+    VarDeclaration *vthis;	// 'this' parameter if this aggregate is nested
+
+    // Special member functions
+    InvariantDeclaration *inv;		// invariant
+    NewDeclaration *aggNew;		// allocator
+    DeleteDeclaration *aggDelete;	// deallocator
+
+#if DMDV2
+    //CtorDeclaration *ctor;
+    Dsymbol *ctor;			// CtorDeclaration or TemplateDeclaration
+    CtorDeclaration *defaultCtor;	// default constructor
+    Dsymbol *aliasthis;			// forward unresolved lookups to aliasthis
+#endif
+
+    FuncDeclarations dtors;	// Array of destructors
+    FuncDeclaration *dtor;	// aggregate destructor
+
+#ifdef IN_GCC
+    Array methods;              // flat list of all methods for debug information
+#endif
+
+    AggregateDeclaration(Loc loc, Identifier *id);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    unsigned size(Loc loc);
+    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
+    Type *getType();
+    void addField(Scope *sc, VarDeclaration *v);
+    int isDeprecated();		// is aggregate deprecated?
+    FuncDeclaration *buildDtor(Scope *sc);
+    int isNested();
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    // For access checking
+    virtual PROT getAccess(Dsymbol *smember);	// determine access to smember
+    int isFriendOf(AggregateDeclaration *cd);
+    int hasPrivateAccess(Dsymbol *smember);	// does smember have private access to members of this class?
+    void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
+
+    enum PROT prot();
+
+#if IN_DMD
+    // Back end
+    Symbol *stag;		// tag symbol for debug data
+    Symbol *sinit;
+    Symbol *toInitializer();
+#endif
+
+    AggregateDeclaration *isAggregateDeclaration() { return this; }
+};
+
+struct AnonymousAggregateDeclaration : AggregateDeclaration
+{
+    AnonymousAggregateDeclaration()
+	: AggregateDeclaration(0, NULL)
+    {
+    }
+
+    AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
+};
+
+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();
+    const char *kind();
+    int needOpAssign();
+    FuncDeclaration *buildOpAssign(Scope *sc);
+    FuncDeclaration *buildPostBlit(Scope *sc);
+    FuncDeclaration *buildCpCtor(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+#if IN_DMD
+    void toObjFile(int multiobj);			// compile to .obj file
+    void toDt(dt_t **pdt);
+    void toDebug();			// to symbolic debug info
+#endif
+
+    StructDeclaration *isStructDeclaration() { return this; }
+
+#if IN_LLVM
+    void codegen(Ir*);
+#endif
+};
+
+struct UnionDeclaration : StructDeclaration
+{
+    UnionDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    const char *kind();
+
+    UnionDeclaration *isUnionDeclaration() { return this; }
+};
+
+// warning: two classes with the same base class share the same
+//   BaseClass instance.
+struct BaseClass
+{
+    Type *type;				// (before semantic processing)
+    enum PROT protection;		// protection for the base interface
+
+    ClassDeclaration *base;
+    int offset;				// 'this' pointer offset
+    Array vtbl;				// for interfaces: Array of FuncDeclaration's
+					// making up the vtbl[]
+
+    int baseInterfaces_dim;
+    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
+					// are a copy of the InterfaceDeclaration::interfaces
+
+    BaseClass();
+    BaseClass(Type *type, enum PROT protection);
+
+    int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance);
+    void copyBaseInterfaces(BaseClasses *);
+};
+
+#if DMDV2
+#define CLASSINFO_SIZE 	(0x3C+16+4)	// value of ClassInfo.size
+#else
+#define CLASSINFO_SIZE 	(0x3C+12+4)	// value of ClassInfo.size
+#endif
+
+struct ClassDeclaration : AggregateDeclaration
+{
+    static ClassDeclaration *object;
+    static ClassDeclaration *classinfo;
+
+    ClassDeclaration *baseClass;	// NULL only if this is Object
+    FuncDeclaration *staticCtor;
+    FuncDeclaration *staticDtor;
+    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
+    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]
+
+    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
+					// rest are Interface's
+
+    int interfaces_dim;
+    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
+					// (does not include baseClass)
+
+    BaseClasses *vtblInterfaces;	// array of base interfaces that have
+					// their own vtbl[]
+
+    ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this ClassDeclaration
+    int com;				// !=0 if this is a COM class (meaning
+					// it derives from IUnknown)
+    int isauto;				// !=0 if this is an auto class
+    int isabstract;			// !=0 if abstract class
+
+    int inuse;				// to prevent recursive attempts
+
+    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isBaseOf2(ClassDeclaration *cd);
+
+    #define OFFSET_RUNTIME 0x76543210
+    virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
+
+    Dsymbol *search(Loc, Identifier *ident, int flags);
+#if DMDV2
+    int isFuncHidden(FuncDeclaration *fd);
+#endif
+    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+    void interfaceSemantic(Scope *sc);
+    int isCOMclass();
+    virtual int isCOMinterface();
+#if DMDV2
+    virtual int isCPPinterface();
+#endif
+    int isAbstract();
+    virtual int vtblOffset();
+    const char *kind();
+    char *mangle();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void addLocalClass(ClassDeclarations *);
+
+#if IN_DMD
+    // Back end
+    void toObjFile(int multiobj);			// compile to .obj file
+    void toDebug();
+    unsigned baseVtblOffset(BaseClass *bc);
+    Symbol *toSymbol();
+    Symbol *toVtblSymbol();
+    void toDt(dt_t **pdt);
+    void toDt2(dt_t **pdt, ClassDeclaration *cd);
+
+    Symbol *vtblsym;
+#endif
+
+    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+
+#if IN_LLVM
+    virtual void codegen(Ir*);
+#endif
+};
+
+struct InterfaceDeclaration : ClassDeclaration
+{
+#if DMDV2
+    int cpp;				// !=0 if this is a C++ interface
+#endif
+    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int isBaseOf(ClassDeclaration *cd, int *poffset);
+    int isBaseOf(BaseClass *bc, int *poffset);
+    const char *kind();
+    int vtblOffset();
+#if DMDV2
+    int isCPPinterface();
+#endif
+    virtual int isCOMinterface();
+
+#if IN_DMD
+    void toObjFile(int multiobj);			// compile to .obj file
+    Symbol *toSymbol();
+#endif
+
+    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+
+#if IN_LLVM
+    void codegen(Ir*);
+#endif
+};
+
+#endif /* DMD_AGGREGATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/aliasthis.c	Sat May 30 17:23:32 2009 +0100
@@ -0,0 +1,72 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2009-2009 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 "identifier.h"
+#include "aliasthis.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "dsymbol.h"
+
+#if DMDV2
+
+
+AliasThis::AliasThis(Loc loc, Identifier *ident)
+    : Dsymbol(NULL)		// it's anonymous (no identifier)
+{
+    this->loc = loc;
+    this->ident = ident;
+}
+
+Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    /* Since there is no semantic information stored here,
+     * we don't need to copy it.
+     */
+    return this;
+}
+
+void AliasThis::semantic(Scope *sc)
+{
+    Dsymbol *parent = sc->parent;
+    if (parent)
+	parent = parent->pastMixin();
+    AggregateDeclaration *ad = NULL;
+    if (parent)
+	ad = parent->isAggregateDeclaration();
+    if (ad)
+    {
+	if (ad->aliasthis)
+	    error("there can be only one alias this");
+	assert(ad->members);
+	Dsymbol *s = ad->search(loc, ident, 0);
+	ad->aliasthis = s;
+    }
+    else
+	error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere");
+}
+
+const char *AliasThis::kind()
+{
+    return "alias this";
+}
+
+void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+    buf->writestring(ident->toChars());
+    buf->writestring(" this;\n");
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/aliasthis.h	Sat May 30 17:23:32 2009 +0100
@@ -0,0 +1,41 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2009-2009 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_ALIASTHIS_H
+#define DMD_ALIASTHIS_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "mars.h"
+#include "dsymbol.h"
+
+/**************************************************************/
+
+#if DMDV2
+
+struct AliasThis : Dsymbol
+{
+   // alias Identifier this;
+    Identifier *ident;
+
+    AliasThis(Loc loc, Identifier *ident);
+
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    AliasThis *isAliasThis() { return this; }
+};
+
+#endif
+
+#endif
--- a/dmd2/arrayop.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/arrayop.c	Sat May 30 17:23:32 2009 +0100
@@ -1,494 +1,505 @@
-
-// 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 <string.h>
-#include <assert.h>
-
-#if _WIN32 || IN_GCC  || IN_LLVM
-#include "mem.h"
-#else
-#include "../root/mem.h"
-#endif
-
-#include "stringtable.h"
-
-#include "expression.h"
-#include "statement.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "scope.h"
-#include "id.h"
-#include "module.h"
-#include "init.h"
-
-
-/***********************************
- * Construct the array operation expression.
- */
-
-Expression *BinExp::arrayOp(Scope *sc)
-{
-    Expressions *arguments = new Expressions();
-
-    /* The expression to generate an array operation for is mangled
-     * into a name to use as the array operation function name.
-     * Mangle in the operands and operators in RPN order, and type.
-     */
-    OutBuffer buf;
-    buf.writestring("_array");
-    buildArrayIdent(&buf, arguments);
-    buf.writeByte('_');
-
-    /* Append deco of array element type
-     */
-#if DMDV2
-    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
-#else
-    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
-#endif
-
-    size_t namelen = buf.offset;
-    buf.writeByte(0);
-    char *name = (char *)buf.extractData();
-
-    /* Look up name in hash table
-     */
-    StringValue *sv = sc->module->arrayfuncs.update(name, namelen);
-    FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue;
-    if (!fd)
-    {
-//     /* Some of the array op functions are written as library functions,
-//      * presumably to optimize them with special CPU vector instructions.
-//      * List those library functions here, in alpha order.
-//      */
-//     static const char *libArrayopFuncs[] =
-//     {
-//         "_arrayExpSliceAddass_a",
-//         "_arrayExpSliceAddass_d",       // T[]+=T
-//         "_arrayExpSliceAddass_f",       // T[]+=T
-//         "_arrayExpSliceAddass_g",
-//         "_arrayExpSliceAddass_h",
-//         "_arrayExpSliceAddass_i",
-//         "_arrayExpSliceAddass_k",
-//         "_arrayExpSliceAddass_s",
-//         "_arrayExpSliceAddass_t",
-//         "_arrayExpSliceAddass_u",
-//         "_arrayExpSliceAddass_w",
-// 
-//         "_arrayExpSliceDivass_d",       // T[]/=T
-//         "_arrayExpSliceDivass_f",       // T[]/=T
-// 
-//         "_arrayExpSliceMinSliceAssign_a",
-//         "_arrayExpSliceMinSliceAssign_d",   // T[]=T-T[]
-//         "_arrayExpSliceMinSliceAssign_f",   // T[]=T-T[]
-//         "_arrayExpSliceMinSliceAssign_g",
-//         "_arrayExpSliceMinSliceAssign_h",
-//         "_arrayExpSliceMinSliceAssign_i",
-//         "_arrayExpSliceMinSliceAssign_k",
-//         "_arrayExpSliceMinSliceAssign_s",
-//         "_arrayExpSliceMinSliceAssign_t",
-//         "_arrayExpSliceMinSliceAssign_u",
-//         "_arrayExpSliceMinSliceAssign_w",
-// 
-//         "_arrayExpSliceMinass_a",
-//         "_arrayExpSliceMinass_d",       // T[]-=T
-//         "_arrayExpSliceMinass_f",       // T[]-=T
-//         "_arrayExpSliceMinass_g",
-//         "_arrayExpSliceMinass_h",
-//         "_arrayExpSliceMinass_i",
-//         "_arrayExpSliceMinass_k",
-//         "_arrayExpSliceMinass_s",
-//         "_arrayExpSliceMinass_t",
-//         "_arrayExpSliceMinass_u",
-//         "_arrayExpSliceMinass_w",
-// 
-//         "_arrayExpSliceMulass_d",       // T[]*=T
-//         "_arrayExpSliceMulass_f",       // T[]*=T
-//         "_arrayExpSliceMulass_i",
-//         "_arrayExpSliceMulass_k",
-//         "_arrayExpSliceMulass_s",
-//         "_arrayExpSliceMulass_t",
-//         "_arrayExpSliceMulass_u",
-//         "_arrayExpSliceMulass_w",
-// 
-//         "_arraySliceExpAddSliceAssign_a",
-//         "_arraySliceExpAddSliceAssign_d",   // T[]=T[]+T
-//         "_arraySliceExpAddSliceAssign_f",   // T[]=T[]+T
-//         "_arraySliceExpAddSliceAssign_g",
-//         "_arraySliceExpAddSliceAssign_h",
-//         "_arraySliceExpAddSliceAssign_i",
-//         "_arraySliceExpAddSliceAssign_k",
-//         "_arraySliceExpAddSliceAssign_s",
-//         "_arraySliceExpAddSliceAssign_t",
-//         "_arraySliceExpAddSliceAssign_u",
-//         "_arraySliceExpAddSliceAssign_w",
-// 
-//         "_arraySliceExpDivSliceAssign_d",   // T[]=T[]/T
-//         "_arraySliceExpDivSliceAssign_f",   // T[]=T[]/T
-// 
-//         "_arraySliceExpMinSliceAssign_a",
-//         "_arraySliceExpMinSliceAssign_d",   // T[]=T[]-T
-//         "_arraySliceExpMinSliceAssign_f",   // T[]=T[]-T
-//         "_arraySliceExpMinSliceAssign_g",
-//         "_arraySliceExpMinSliceAssign_h",
-//         "_arraySliceExpMinSliceAssign_i",
-//         "_arraySliceExpMinSliceAssign_k",
-//         "_arraySliceExpMinSliceAssign_s",
-//         "_arraySliceExpMinSliceAssign_t",
-//         "_arraySliceExpMinSliceAssign_u",
-//         "_arraySliceExpMinSliceAssign_w",
-// 
-//         "_arraySliceExpMulSliceAddass_d",   // T[] += T[]*T
-//         "_arraySliceExpMulSliceAddass_f",
-//         "_arraySliceExpMulSliceAddass_r",
-// 
-//         "_arraySliceExpMulSliceAssign_d",   // T[]=T[]*T
-//         "_arraySliceExpMulSliceAssign_f",   // T[]=T[]*T
-//         "_arraySliceExpMulSliceAssign_i",
-//         "_arraySliceExpMulSliceAssign_k",
-//         "_arraySliceExpMulSliceAssign_s",
-//         "_arraySliceExpMulSliceAssign_t",
-//         "_arraySliceExpMulSliceAssign_u",
-//         "_arraySliceExpMulSliceAssign_w",
-// 
-//         "_arraySliceExpMulSliceMinass_d",   // T[] -= T[]*T
-//         "_arraySliceExpMulSliceMinass_f",
-//         "_arraySliceExpMulSliceMinass_r",
-// 
-//         "_arraySliceSliceAddSliceAssign_a",
-//         "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
-//         "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
-//         "_arraySliceSliceAddSliceAssign_g",
-//         "_arraySliceSliceAddSliceAssign_h",
-//         "_arraySliceSliceAddSliceAssign_i",
-//         "_arraySliceSliceAddSliceAssign_k",
-//         "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
-//         "_arraySliceSliceAddSliceAssign_s",
-//         "_arraySliceSliceAddSliceAssign_t",
-//         "_arraySliceSliceAddSliceAssign_u",
-//         "_arraySliceSliceAddSliceAssign_w",
-// 
-//         "_arraySliceSliceAddass_a",
-//         "_arraySliceSliceAddass_d",     // T[]+=T[]
-//         "_arraySliceSliceAddass_f",     // T[]+=T[]
-//         "_arraySliceSliceAddass_g",
-//         "_arraySliceSliceAddass_h",
-//         "_arraySliceSliceAddass_i",
-//         "_arraySliceSliceAddass_k",
-//         "_arraySliceSliceAddass_s",
-//         "_arraySliceSliceAddass_t",
-//         "_arraySliceSliceAddass_u",
-//         "_arraySliceSliceAddass_w",
-// 
-//         "_arraySliceSliceMinSliceAssign_a",
-//         "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
-//         "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
-//         "_arraySliceSliceMinSliceAssign_g",
-//         "_arraySliceSliceMinSliceAssign_h",
-//         "_arraySliceSliceMinSliceAssign_i",
-//         "_arraySliceSliceMinSliceAssign_k",
-//         "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
-//         "_arraySliceSliceMinSliceAssign_s",
-//         "_arraySliceSliceMinSliceAssign_t",
-//         "_arraySliceSliceMinSliceAssign_u",
-//         "_arraySliceSliceMinSliceAssign_w",
-// 
-//         "_arraySliceSliceMinass_a",
-//         "_arraySliceSliceMinass_d",     // T[]-=T[]
-//         "_arraySliceSliceMinass_f",     // T[]-=T[]
-//         "_arraySliceSliceMinass_g",
-//         "_arraySliceSliceMinass_h",
-//         "_arraySliceSliceMinass_i",
-//         "_arraySliceSliceMinass_k",
-//         "_arraySliceSliceMinass_s",
-//         "_arraySliceSliceMinass_t",
-//         "_arraySliceSliceMinass_u",
-//         "_arraySliceSliceMinass_w",
-// 
-//         "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
-//         "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
-//         "_arraySliceSliceMulSliceAssign_i",
-//         "_arraySliceSliceMulSliceAssign_k",
-//         "_arraySliceSliceMulSliceAssign_s",
-//         "_arraySliceSliceMulSliceAssign_t",
-//         "_arraySliceSliceMulSliceAssign_u",
-//         "_arraySliceSliceMulSliceAssign_w",
-// 
-//         "_arraySliceSliceMulass_d",     // T[]*=T[]
-//         "_arraySliceSliceMulass_f",     // T[]*=T[]
-//         "_arraySliceSliceMulass_i",
-//         "_arraySliceSliceMulass_k",
-//         "_arraySliceSliceMulass_s",
-//         "_arraySliceSliceMulass_t",
-//         "_arraySliceSliceMulass_u",
-//         "_arraySliceSliceMulass_w",
-//     };
-// 
-//     int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
-//     if (i == -1)
-//     {
-// #ifdef DEBUG    // Make sure our array is alphabetized
-//         for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
-//         {
-//         if (strcmp(name, libArrayopFuncs[i]) == 0)
-//             assert(0);
-//         }
-// #endif
-
-        /* Not in library, so generate it.
-         * Construct the function body:
-         *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
-         *      loopbody;
-         *  return p;
-         */
-
-        Arguments *fparams = new Arguments();
-        Expression *loopbody = buildArrayLoop(fparams);
-        Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/];
-#if DMDV1
-        // for (size_t i = 0; i < p.length; i++)
-        Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
-        Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
-        Statement *s1 = new ForStatement(0,
-        new DeclarationStatement(0, d),
-        new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
-        new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
-        new ExpStatement(0, loopbody));
-#else
-        // foreach (i; 0 .. p.length)
-        Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
-        new Argument(0, NULL, Id::p, NULL),
-        new IntegerExp(0, 0, Type::tint32),
-        new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
-        new ExpStatement(0, loopbody));
-#endif
-        Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
-        //printf("s2: %s\n", s2->toChars());
-        Statement *fbody = new CompoundStatement(0, s1, s2);
-
-        /* Construct the function
-         */
-        TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
-        //printf("ftype: %s\n", ftype->toChars());
-        fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype);
-        fd->fbody = fbody;
-        fd->protection = PROTprotected;
-        fd->linkage = LINKd;
-
-        // special attention for array ops
-        fd->isArrayOp = true;
-
-        sc->module->members->push(fd);
-
-        sc = sc->push();
-        sc->parent = sc->module;
-        sc->stc = 0;
-        sc->linkage = LINKd;
-        fd->semantic(sc);
-        sc->pop();
-//     }
-//     else
-//     {   /* In library, refer to it.
-//          */
-//         // FIXME
-//         fd = FuncDeclaration::genCfunc(NULL, type, name);
-//     }
-    sv->ptrvalue = fd;  // cache symbol in hash table
-    }
-
-    /* Call the function fd(arguments)
-     */
-    Expression *ec = new VarExp(0, fd);
-    Expression *e = new CallExp(loc, ec, arguments);
-    e->type = type;
-    return e;
-}
-
-/******************************************
- * Construct the identifier for the array operation function,
- * and build the argument list to pass to it.
- */
-
-void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
-{
-    buf->writestring("Exp");
-    arguments->shift(this);
-}
-
-void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
-{
-    buf->writestring("Slice");
-    arguments->shift(this);
-}
-
-void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
-{
-    /* Evaluate assign expressions right to left
-     */
-    e2->buildArrayIdent(buf, arguments);
-    e1->buildArrayIdent(buf, arguments);
-    buf->writestring("Assign");
-}
-
-#define X(Str) \
-void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
-{							\
-    /* Evaluate assign expressions right to left	\
-     */							\
-    e2->buildArrayIdent(buf, arguments);		\
-    e1->buildArrayIdent(buf, arguments);		\
-    buf->writestring(#Str);				\
-    buf->writestring("ass");				\
-}
-
-X(Add)
-X(Min)
-X(Mul)
-X(Div)
-X(Mod)
-X(Xor)
-X(And)
-X(Or)
-
-#undef X
-
-void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
-{
-    e1->buildArrayIdent(buf, arguments);
-    buf->writestring("Neg");
-}
-
-void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
-{
-    e1->buildArrayIdent(buf, arguments);
-    buf->writestring("Com");
-}
-
-#define X(Str) \
-void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)	\
-{									\
-    /* Evaluate assign expressions left to right			\
-     */									\
-    e1->buildArrayIdent(buf, arguments);				\
-    e2->buildArrayIdent(buf, arguments);				\
-    buf->writestring(#Str);						\
-}
-
-X(Add)
-X(Min)
-X(Mul)
-X(Div)
-X(Mod)
-X(Xor)
-X(And)
-X(Or)
-
-#undef X
-
-/******************************************
- * Construct the inner loop for the array operation function,
- * and build the parameter list.
- */
-
-Expression *Expression::buildArrayLoop(Arguments *fparams)
-{
-    Identifier *id = Identifier::generateId("c", fparams->dim);
-    Argument *param = new Argument(0, type, id, NULL);
-    fparams->shift(param);
-    Expression *e = new IdentifierExp(0, id);
-    return e;
-}
-
-Expression *SliceExp::buildArrayLoop(Arguments *fparams)
-{
-    Identifier *id = Identifier::generateId("p", fparams->dim);
-    Argument *param = new Argument(STCconst, type, id, NULL);
-    fparams->shift(param);
-    Expression *e = new IdentifierExp(0, id);
-    Expressions *arguments = new Expressions();
-    Expression *index = new IdentifierExp(0, Id::p);
-    arguments->push(index);
-    e = new ArrayExp(0, e, arguments);
-    return e;
-}
-
-Expression *AssignExp::buildArrayLoop(Arguments *fparams)
-{
-    /* Evaluate assign expressions right to left
-     */
-    Expression *ex2 = e2->buildArrayLoop(fparams);
-    Expression *ex1 = e1->buildArrayLoop(fparams);
-    Argument *param = (Argument *)fparams->data[0];
-    param->storageClass = 0;
-    Expression *e = new AssignExp(0, ex1, ex2);
-    return e;
-}
-
-#define X(Str) \
-Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams)	\
-{								\
-    /* Evaluate assign expressions right to left		\
-     */								\
-    Expression *ex2 = e2->buildArrayLoop(fparams);		\
-    Expression *ex1 = e1->buildArrayLoop(fparams);		\
-    Argument *param = (Argument *)fparams->data[0];		\
-    param->storageClass = 0;					\
-    Expression *e = new Str##AssignExp(0, ex1, ex2);		\
-    return e;							\
-}
-
-X(Add)
-X(Min)
-X(Mul)
-X(Div)
-X(Mod)
-X(Xor)
-X(And)
-X(Or)
-
-#undef X
-
-Expression *NegExp::buildArrayLoop(Arguments *fparams)
-{
-    Expression *ex1 = e1->buildArrayLoop(fparams);
-    Expression *e = new NegExp(0, ex1);
-    return e;
-}
-
-Expression *ComExp::buildArrayLoop(Arguments *fparams)
-{
-    Expression *ex1 = e1->buildArrayLoop(fparams);
-    Expression *e = new ComExp(0, ex1);
-    return e;
-}
-
-#define X(Str) \
-Expression *Str##Exp::buildArrayLoop(Arguments *fparams)	\
-{								\
-    /* Evaluate assign expressions left to right		\
-     */								\
-    Expression *ex1 = e1->buildArrayLoop(fparams);		\
-    Expression *ex2 = e2->buildArrayLoop(fparams);		\
-    Expression *e = new Str##Exp(0, ex1, ex2);			\
-    return e;							\
-}
-
-X(Add)
-X(Min)
-X(Mul)
-X(Div)
-X(Mod)
-X(Xor)
-X(And)
-X(Or)
-
-#undef X
-
-
+
+// 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 <string.h>
+#include <assert.h>
+
+#include "rmem.h"
+
+#include "stringtable.h"
+
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "scope.h"
+#include "id.h"
+#include "module.h"
+#include "init.h"
+
+#if IN_DMD
+extern int binary(const char *p , const char **tab, int high);
+
+/**************************************
+ * Hash table of array op functions already generated or known about.
+ */
+
+StringTable arrayfuncs;
+#endif
+
+/***********************************
+ * Construct the array operation expression.
+ */
+
+Expression *BinExp::arrayOp(Scope *sc)
+{
+    Expressions *arguments = new Expressions();
+
+    /* The expression to generate an array operation for is mangled
+     * into a name to use as the array operation function name.
+     * Mangle in the operands and operators in RPN order, and type.
+     */
+    OutBuffer buf;
+    buf.writestring("_array");
+    buildArrayIdent(&buf, arguments);
+    buf.writeByte('_');
+
+    /* Append deco of array element type
+     */
+#if DMDV2
+    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
+#else
+    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
+#endif
+
+    size_t namelen = buf.offset;
+    buf.writeByte(0);
+    char *name = (char *)buf.extractData();
+
+    /* Look up name in hash table
+     */
+#if IN_LLVM
+    StringValue *sv = sc->module->arrayfuncs.update(name, namelen);
+#else
+    StringValue *sv = arrayfuncs.update(name, namelen);
+#endif
+    FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue;
+    if (!fd)
+    {
+#if IN_DMD
+	/* Some of the array op functions are written as library functions,
+	 * presumably to optimize them with special CPU vector instructions.
+	 * List those library functions here, in alpha order.
+	 */
+	static const char *libArrayopFuncs[] =
+	{
+	    "_arrayExpSliceAddass_a",
+	    "_arrayExpSliceAddass_d",		// T[]+=T
+	    "_arrayExpSliceAddass_f",		// T[]+=T
+	    "_arrayExpSliceAddass_g",
+	    "_arrayExpSliceAddass_h",
+	    "_arrayExpSliceAddass_i",
+	    "_arrayExpSliceAddass_k",
+	    "_arrayExpSliceAddass_s",
+	    "_arrayExpSliceAddass_t",
+	    "_arrayExpSliceAddass_u",
+	    "_arrayExpSliceAddass_w",
+
+	    "_arrayExpSliceDivass_d",		// T[]/=T
+	    "_arrayExpSliceDivass_f",		// T[]/=T
+
+	    "_arrayExpSliceMinSliceAssign_a",
+	    "_arrayExpSliceMinSliceAssign_d",	// T[]=T-T[]
+	    "_arrayExpSliceMinSliceAssign_f",	// T[]=T-T[]
+	    "_arrayExpSliceMinSliceAssign_g",
+	    "_arrayExpSliceMinSliceAssign_h",
+	    "_arrayExpSliceMinSliceAssign_i",
+	    "_arrayExpSliceMinSliceAssign_k",
+	    "_arrayExpSliceMinSliceAssign_s",
+	    "_arrayExpSliceMinSliceAssign_t",
+	    "_arrayExpSliceMinSliceAssign_u",
+	    "_arrayExpSliceMinSliceAssign_w",
+
+	    "_arrayExpSliceMinass_a",
+	    "_arrayExpSliceMinass_d",		// T[]-=T
+	    "_arrayExpSliceMinass_f",		// T[]-=T
+	    "_arrayExpSliceMinass_g",
+	    "_arrayExpSliceMinass_h",
+	    "_arrayExpSliceMinass_i",
+	    "_arrayExpSliceMinass_k",
+	    "_arrayExpSliceMinass_s",
+	    "_arrayExpSliceMinass_t",
+	    "_arrayExpSliceMinass_u",
+	    "_arrayExpSliceMinass_w",
+
+	    "_arrayExpSliceMulass_d",		// T[]*=T
+	    "_arrayExpSliceMulass_f",		// T[]*=T
+	    "_arrayExpSliceMulass_i",
+	    "_arrayExpSliceMulass_k",
+	    "_arrayExpSliceMulass_s",
+	    "_arrayExpSliceMulass_t",
+	    "_arrayExpSliceMulass_u",
+	    "_arrayExpSliceMulass_w",
+
+	    "_arraySliceExpAddSliceAssign_a",
+	    "_arraySliceExpAddSliceAssign_d",	// T[]=T[]+T
+	    "_arraySliceExpAddSliceAssign_f",	// T[]=T[]+T
+	    "_arraySliceExpAddSliceAssign_g",
+	    "_arraySliceExpAddSliceAssign_h",
+	    "_arraySliceExpAddSliceAssign_i",
+	    "_arraySliceExpAddSliceAssign_k",
+	    "_arraySliceExpAddSliceAssign_s",
+	    "_arraySliceExpAddSliceAssign_t",
+	    "_arraySliceExpAddSliceAssign_u",
+	    "_arraySliceExpAddSliceAssign_w",
+
+	    "_arraySliceExpDivSliceAssign_d",	// T[]=T[]/T
+	    "_arraySliceExpDivSliceAssign_f",	// T[]=T[]/T
+
+	    "_arraySliceExpMinSliceAssign_a",
+	    "_arraySliceExpMinSliceAssign_d",	// T[]=T[]-T
+	    "_arraySliceExpMinSliceAssign_f",	// T[]=T[]-T
+	    "_arraySliceExpMinSliceAssign_g",
+	    "_arraySliceExpMinSliceAssign_h",
+	    "_arraySliceExpMinSliceAssign_i",
+	    "_arraySliceExpMinSliceAssign_k",
+	    "_arraySliceExpMinSliceAssign_s",
+	    "_arraySliceExpMinSliceAssign_t",
+	    "_arraySliceExpMinSliceAssign_u",
+	    "_arraySliceExpMinSliceAssign_w",
+
+	    "_arraySliceExpMulSliceAddass_d",	// T[] += T[]*T
+	    "_arraySliceExpMulSliceAddass_f",
+	    "_arraySliceExpMulSliceAddass_r",
+
+	    "_arraySliceExpMulSliceAssign_d",	// T[]=T[]*T
+	    "_arraySliceExpMulSliceAssign_f",	// T[]=T[]*T
+	    "_arraySliceExpMulSliceAssign_i",
+	    "_arraySliceExpMulSliceAssign_k",
+	    "_arraySliceExpMulSliceAssign_s",
+	    "_arraySliceExpMulSliceAssign_t",
+	    "_arraySliceExpMulSliceAssign_u",
+	    "_arraySliceExpMulSliceAssign_w",
+
+	    "_arraySliceExpMulSliceMinass_d",	// T[] -= T[]*T
+	    "_arraySliceExpMulSliceMinass_f",
+	    "_arraySliceExpMulSliceMinass_r",
+
+	    "_arraySliceSliceAddSliceAssign_a",
+	    "_arraySliceSliceAddSliceAssign_d",	// T[]=T[]+T[]
+	    "_arraySliceSliceAddSliceAssign_f",	// T[]=T[]+T[]
+	    "_arraySliceSliceAddSliceAssign_g",
+	    "_arraySliceSliceAddSliceAssign_h",
+	    "_arraySliceSliceAddSliceAssign_i",
+	    "_arraySliceSliceAddSliceAssign_k",
+	    "_arraySliceSliceAddSliceAssign_r",	// T[]=T[]+T[]
+	    "_arraySliceSliceAddSliceAssign_s",
+	    "_arraySliceSliceAddSliceAssign_t",
+	    "_arraySliceSliceAddSliceAssign_u",
+	    "_arraySliceSliceAddSliceAssign_w",
+
+	    "_arraySliceSliceAddass_a",
+	    "_arraySliceSliceAddass_d",		// T[]+=T[]
+	    "_arraySliceSliceAddass_f",		// T[]+=T[]
+	    "_arraySliceSliceAddass_g",
+	    "_arraySliceSliceAddass_h",
+	    "_arraySliceSliceAddass_i",
+	    "_arraySliceSliceAddass_k",
+	    "_arraySliceSliceAddass_s",
+	    "_arraySliceSliceAddass_t",
+	    "_arraySliceSliceAddass_u",
+	    "_arraySliceSliceAddass_w",
+
+	    "_arraySliceSliceMinSliceAssign_a",
+	    "_arraySliceSliceMinSliceAssign_d",	// T[]=T[]-T[]
+	    "_arraySliceSliceMinSliceAssign_f",	// T[]=T[]-T[]
+	    "_arraySliceSliceMinSliceAssign_g",
+	    "_arraySliceSliceMinSliceAssign_h",
+	    "_arraySliceSliceMinSliceAssign_i",
+	    "_arraySliceSliceMinSliceAssign_k",
+	    "_arraySliceSliceMinSliceAssign_r",	// T[]=T[]-T[]
+	    "_arraySliceSliceMinSliceAssign_s",
+	    "_arraySliceSliceMinSliceAssign_t",
+	    "_arraySliceSliceMinSliceAssign_u",
+	    "_arraySliceSliceMinSliceAssign_w",
+
+	    "_arraySliceSliceMinass_a",
+	    "_arraySliceSliceMinass_d",		// T[]-=T[]
+	    "_arraySliceSliceMinass_f",		// T[]-=T[]
+	    "_arraySliceSliceMinass_g",
+	    "_arraySliceSliceMinass_h",
+	    "_arraySliceSliceMinass_i",
+	    "_arraySliceSliceMinass_k",
+	    "_arraySliceSliceMinass_s",
+	    "_arraySliceSliceMinass_t",
+	    "_arraySliceSliceMinass_u",
+	    "_arraySliceSliceMinass_w",
+
+	    "_arraySliceSliceMulSliceAssign_d",	// T[]=T[]*T[]
+	    "_arraySliceSliceMulSliceAssign_f",	// T[]=T[]*T[]
+	    "_arraySliceSliceMulSliceAssign_i",
+	    "_arraySliceSliceMulSliceAssign_k",
+	    "_arraySliceSliceMulSliceAssign_s",
+	    "_arraySliceSliceMulSliceAssign_t",
+	    "_arraySliceSliceMulSliceAssign_u",
+	    "_arraySliceSliceMulSliceAssign_w",
+
+	    "_arraySliceSliceMulass_d",		// T[]*=T[]
+	    "_arraySliceSliceMulass_f",		// T[]*=T[]
+	    "_arraySliceSliceMulass_i",
+	    "_arraySliceSliceMulass_k",
+	    "_arraySliceSliceMulass_s",
+	    "_arraySliceSliceMulass_t",
+	    "_arraySliceSliceMulass_u",
+	    "_arraySliceSliceMulass_w",
+	};
+
+	int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
+	if (i == -1)
+	{
+#ifdef DEBUG	// Make sure our array is alphabetized
+	    for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
+	    {
+		if (strcmp(name, libArrayopFuncs[i]) == 0)
+		    assert(0);
+	    }
+#endif
+#endif
+	    /* Not in library, so generate it.
+	     * Construct the function body:
+	     *	foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
+	     *	    loopbody;
+	     *	return p;
+	     */
+
+	    Arguments *fparams = new Arguments();
+	    Expression *loopbody = buildArrayLoop(fparams);
+	    Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/];
+#if DMDV1
+	    // for (size_t i = 0; i < p.length; i++)
+	    Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
+	    Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
+	    Statement *s1 = new ForStatement(0,
+		new DeclarationStatement(0, d),
+		new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
+		new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
+		new ExpStatement(0, loopbody));
+#else
+	    // foreach (i; 0 .. p.length)
+	    Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
+		new Argument(0, NULL, Id::p, NULL),
+		new IntegerExp(0, 0, Type::tint32),
+		new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
+		new ExpStatement(0, loopbody));
+#endif
+	    Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
+	    //printf("s2: %s\n", s2->toChars());
+	    Statement *fbody = new CompoundStatement(0, s1, s2);
+
+	    /* Construct the function
+	     */
+	    TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
+	    //printf("ftype: %s\n", ftype->toChars());
+	    fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype);
+	    fd->fbody = fbody;
+	    fd->protection = PROTpublic;
+	    fd->linkage = LINKd;
+
+   		// special attention for array ops
+        fd->isArrayOp = true;
+
+	    sc->module->importedFrom->members->push(fd);
+
+	    sc = sc->push();
+	    sc->parent = sc->module->importedFrom;
+	    sc->stc = 0;
+	    sc->linkage = LINKc;
+	    fd->semantic(sc);
+	    sc->pop();
+#if IN_DMD
+	}
+	else
+	{   /* In library, refer to it.
+	     */
+	    fd = FuncDeclaration::genCfunc(type, name);
+	}
+#endif
+	sv->ptrvalue = fd;	// cache symbol in hash table
+    }
+
+    /* Call the function fd(arguments)
+     */
+    Expression *ec = new VarExp(0, fd);
+    Expression *e = new CallExp(loc, ec, arguments);
+    e->type = type;
+    return e;
+}
+
+/******************************************
+ * Construct the identifier for the array operation function,
+ * and build the argument list to pass to it.
+ */
+
+void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    buf->writestring("Exp");
+    arguments->shift(this);
+}
+
+void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    buf->writestring("Slice");
+    arguments->shift(this);
+}
+
+void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    /* Evaluate assign expressions right to left
+     */
+    e2->buildArrayIdent(buf, arguments);
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Assign");
+}
+
+#define X(Str) \
+void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
+{							\
+    /* Evaluate assign expressions right to left	\
+     */							\
+    e2->buildArrayIdent(buf, arguments);		\
+    e1->buildArrayIdent(buf, arguments);		\
+    buf->writestring(#Str);				\
+    buf->writestring("ass");				\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Neg");
+}
+
+void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Com");
+}
+
+#define X(Str) \
+void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)	\
+{									\
+    /* Evaluate assign expressions left to right			\
+     */									\
+    e1->buildArrayIdent(buf, arguments);				\
+    e2->buildArrayIdent(buf, arguments);				\
+    buf->writestring(#Str);						\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+/******************************************
+ * Construct the inner loop for the array operation function,
+ * and build the parameter list.
+ */
+
+Expression *Expression::buildArrayLoop(Arguments *fparams)
+{
+    Identifier *id = Identifier::generateId("c", fparams->dim);
+    Argument *param = new Argument(0, type, id, NULL);
+    fparams->shift(param);
+    Expression *e = new IdentifierExp(0, id);
+    return e;
+}
+
+Expression *SliceExp::buildArrayLoop(Arguments *fparams)
+{
+    Identifier *id = Identifier::generateId("p", fparams->dim);
+    Argument *param = new Argument(STCconst, type, id, NULL);
+    fparams->shift(param);
+    Expression *e = new IdentifierExp(0, id);
+    Expressions *arguments = new Expressions();
+    Expression *index = new IdentifierExp(0, Id::p);
+    arguments->push(index);
+    e = new ArrayExp(0, e, arguments);
+    return e;
+}
+
+Expression *AssignExp::buildArrayLoop(Arguments *fparams)
+{
+    /* Evaluate assign expressions right to left
+     */
+    Expression *ex2 = e2->buildArrayLoop(fparams);
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Argument *param = (Argument *)fparams->data[0];
+    param->storageClass = 0;
+    Expression *e = new AssignExp(0, ex1, ex2);
+    return e;
+}
+
+#define X(Str) \
+Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams)	\
+{								\
+    /* Evaluate assign expressions right to left		\
+     */								\
+    Expression *ex2 = e2->buildArrayLoop(fparams);		\
+    Expression *ex1 = e1->buildArrayLoop(fparams);		\
+    Argument *param = (Argument *)fparams->data[0];		\
+    param->storageClass = 0;					\
+    Expression *e = new Str##AssignExp(0, ex1, ex2);		\
+    return e;							\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+Expression *NegExp::buildArrayLoop(Arguments *fparams)
+{
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Expression *e = new NegExp(0, ex1);
+    return e;
+}
+
+Expression *ComExp::buildArrayLoop(Arguments *fparams)
+{
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Expression *e = new ComExp(0, ex1);
+    return e;
+}
+
+#define X(Str) \
+Expression *Str##Exp::buildArrayLoop(Arguments *fparams)	\
+{								\
+    /* Evaluate assign expressions left to right		\
+     */								\
+    Expression *ex1 = e1->buildArrayLoop(fparams);		\
+    Expression *ex2 = e2->buildArrayLoop(fparams);		\
+    Expression *e = new Str##Exp(0, ex1, ex2);			\
+    return e;							\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+
--- a/dmd2/attrib.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/attrib.c	Sat May 30 17:23:32 2009 +0100
@@ -1,1483 +1,1553 @@
-
-// 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 <stdlib.h>
-#include <assert.h>
-
-#if _WIN32 || IN_GCC || IN_LLVM
-#include "mem.h"
-#elif POSIX
-#include "../root/mem.h"
-#endif
-
-#include "init.h"
-#include "declaration.h"
-#include "attrib.h"
-#include "cond.h"
-#include "scope.h"
-#include "id.h"
-#include "expression.h"
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "module.h"
-#include "parse.h"
-#include "template.h"
-
-#include "../gen/enums.h"
-
-
-#include "llvm/Support/CommandLine.h"
-
-static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore",
-    llvm::cl::desc("Ignore unsupported pragmas"),
-    llvm::cl::ZeroOrMore);
-
-
-
-extern void obj_includelib(const char *name);
-void obj_startaddress(Symbol *s);
-
-
-/********************************* AttribDeclaration ****************************/
-
-AttribDeclaration::AttribDeclaration(Array *decl)
-	: Dsymbol()
-{
-    this->decl = decl;
-}
-
-Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd)
-{
-    return decl;
-}
-
-int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
-{
-    int m = 0;
-    Array *d = include(sc, sd);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    m |= s->addMember(sc, sd, m | memnum);
-	}
-    }
-    return m;
-}
-
-void AttribDeclaration::semantic(Scope *sc)
-{
-    Array *d = include(sc, NULL);
-
-    //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)d->data[i];
-
-	    s->semantic(sc);
-	}
-    }
-}
-
-void AttribDeclaration::semantic2(Scope *sc)
-{
-    Array *d = include(sc, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    s->semantic2(sc);
-	}
-    }
-}
-
-void AttribDeclaration::semantic3(Scope *sc)
-{
-    Array *d = include(sc, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    s->semantic3(sc);
-	}
-    }
-}
-
-void AttribDeclaration::inlineScan()
-{
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
-	    s->inlineScan();
-	}
-    }
-}
-
-void AttribDeclaration::addComment(unsigned char *comment)
-{
-    if (comment)
-    {
-	Array *d = include(NULL, NULL);
-
-	if (d)
-	{
-	    for (unsigned i = 0; i < d->dim; i++)
-	    {   Dsymbol *s = (Dsymbol *)d->data[i];
-		//printf("AttribDeclaration::addComment %s\n", s->toChars());
-		s->addComment(comment);
-	    }
-	}
-    }
-}
-
-void AttribDeclaration::emitComment(Scope *sc)
-{
-    //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
-
-    /* If generating doc comment, skip this because if we're inside
-     * a template, then include(NULL, NULL) will fail.
-     */
-//    if (sc->docbuf)
-//	return;
-
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	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(int multiobj)
-{
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    s->toObjFile(multiobj);
-	}
-    }
-}
-
-int AttribDeclaration::cvMember(unsigned char *p)
-{
-    int nwritten = 0;
-    int n;
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    n = s->cvMember(p);
-	    if (p)
-		p += n;
-	    nwritten += n;
-	}
-    }
-    return nwritten;
-}
-
-int AttribDeclaration::hasPointers()
-{
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (size_t i = 0; i < d->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)d->data[i];
-	    if (s->hasPointers())
-		return 1;
-	}
-    }
-    return 0;
-}
-
-const char *AttribDeclaration::kind()
-{
-    return "attribute";
-}
-
-int AttribDeclaration::oneMember(Dsymbol **ps)
-{
-    Array *d = include(NULL, NULL);
-
-    return Dsymbol::oneMembers(d, ps);
-}
-
-void AttribDeclaration::checkCtorConstInit()
-{
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    s->checkCtorConstInit();
-	}
-    }
-}
-
-/****************************************
- */
-
-void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
-{
-    Array *d = include(NULL, NULL);
-
-    if (d)
-    {
-	for (unsigned i = 0; i < d->dim; i++)
-	{   Dsymbol *s = (Dsymbol *)d->data[i];
-	    s->addLocalClass(aclasses);
-	}
-    }
-}
-
-
-void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    if (decl)
-    {
-	buf->writenl();
-	buf->writeByte('{');
-	buf->writenl();
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    buf->writestring("    ");
-	    s->toCBuffer(buf, hgs);
-	}
-	buf->writeByte('}');
-    }
-    else
-	buf->writeByte(';');
-    buf->writenl();
-}
-
-/************************* StorageClassDeclaration ****************************/
-
-StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl)
-	: AttribDeclaration(decl)
-{
-    this->stc = stc;
-}
-
-Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
-{
-    StorageClassDeclaration *scd;
-
-    assert(!s);
-    scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
-    return scd;
-}
-
-void StorageClassDeclaration::semantic(Scope *sc)
-{
-    if (decl)
-    {	unsigned stc_save = sc->stc;
-
-	/* These sets of storage classes are mutually exclusive,
-	 * so choose the innermost or most recent one.
-	 */
-	if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest))
-	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest);
-	if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest))
-	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest);
-	if (stc & (STCconst | STCinvariant | STCmanifest))
-	    sc->stc &= ~(STCconst | STCinvariant | STCmanifest);
-	sc->stc |= stc;
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic(sc);
-	}
-	sc->stc = stc_save;
-    }
-    else
-	sc->stc = stc;
-}
-
-void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    struct SCstring
-    {
-	int stc;
-	enum TOK tok;
-    };
-
-    static SCstring table[] =
-    {
-	{ STCauto,         TOKauto },
-	{ STCscope,        TOKscope },
-	{ STCstatic,       TOKstatic },
-	{ STCextern,       TOKextern },
-	{ STCconst,        TOKconst },
-	{ STCinvariant,    TOKimmutable },
-	{ STCshared,       TOKshared },
-	{ STCfinal,        TOKfinal },
-	{ STCabstract,     TOKabstract },
-	{ STCsynchronized, TOKsynchronized },
-	{ STCdeprecated,   TOKdeprecated },
-	{ STCoverride,     TOKoverride },
-	{ STCnothrow,      TOKnothrow },
-	{ STCpure,         TOKpure },
-	{ STCref,          TOKref },
-	{ STCtls,          TOKtls },
-    };
-
-    int written = 0;
-    for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
-    {
-	if (stc & table[i].stc)
-	{
-	    if (written)
-		buf->writeByte(' ');
-	    written = 1;
-	    buf->writestring(Token::toChars(table[i].tok));
-	}
-    }
-
-    AttribDeclaration::toCBuffer(buf, hgs);
-}
-
-/********************************* LinkDeclaration ****************************/
-
-LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl)
-	: AttribDeclaration(decl)
-{
-    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
-    linkage = p;
-}
-
-Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
-{
-    LinkDeclaration *ld;
-
-    assert(!s);
-    ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
-    return ld;
-}
-
-void LinkDeclaration::semantic(Scope *sc)
-{
-    //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl);
-    if (decl)
-    {	enum LINK linkage_save = sc->linkage;
-
-	sc->linkage = linkage;
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic(sc);
-	}
-	sc->linkage = linkage_save;
-    }
-    else
-    {
-	sc->linkage = linkage;
-    }
-}
-
-void LinkDeclaration::semantic3(Scope *sc)
-{
-    //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl);
-    if (decl)
-    {	enum LINK linkage_save = sc->linkage;
-
-	sc->linkage = linkage;
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic3(sc);
-	}
-	sc->linkage = linkage_save;
-    }
-    else
-    {
-	sc->linkage = linkage;
-    }
-}
-
-void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{   const char *p;
-
-    switch (linkage)
-    {
-	case LINKd:		p = "D";		break;
-	case LINKc:		p = "C";		break;
-	case LINKcpp:		p = "C++";		break;
-	case LINKwindows:	p = "Windows";		break;
-	case LINKpascal:	p = "Pascal";		break;
-
-    // LDC
-    case LINKintrinsic: p = "Intrinsic"; break;
-
-	default:
-	    assert(0);
-	    break;
-    }
-    buf->writestring("extern (");
-    buf->writestring(p);
-    buf->writestring(") ");
-    AttribDeclaration::toCBuffer(buf, hgs);
-}
-
-char *LinkDeclaration::toChars()
-{
-    return (char *)"extern ()";
-}
-
-/********************************* ProtDeclaration ****************************/
-
-ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl)
-	: AttribDeclaration(decl)
-{
-    protection = p;
-    //printf("decl = %p\n", decl);
-}
-
-Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
-{
-    ProtDeclaration *pd;
-
-    assert(!s);
-    pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
-    return pd;
-}
-
-void ProtDeclaration::semantic(Scope *sc)
-{
-    if (decl)
-    {	enum PROT protection_save = sc->protection;
-	int explicitProtection_save = sc->explicitProtection;
-
-	sc->protection = protection;
-	sc->explicitProtection = 1;
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic(sc);
-	}
-	sc->protection = protection_save;
-	sc->explicitProtection = explicitProtection_save;
-    }
-    else
-    {	sc->protection = protection;
-	sc->explicitProtection = 1;
-    }
-}
-
-void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{   const char *p;
-
-    switch (protection)
-    {
-	case PROTprivate:	p = "private";		break;
-	case PROTpackage:	p = "package";		break;
-	case PROTprotected:	p = "protected";	break;
-	case PROTpublic:	p = "public";		break;
-	case PROTexport:	p = "export";		break;
-	default:
-	    assert(0);
-	    break;
-    }
-    buf->writestring(p);
-    AttribDeclaration::toCBuffer(buf, hgs);
-}
-
-/********************************* AlignDeclaration ****************************/
-
-AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl)
-	: AttribDeclaration(decl)
-{
-    this->loc = loc;
-    salign = sa;
-}
-
-Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
-{
-    AlignDeclaration *ad;
-
-    assert(!s);
-    ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl));
-    return ad;
-}
-
-void AlignDeclaration::semantic(Scope *sc)
-{
-// LDC
-// we only support packed structs, as from the spec: align(1) struct Packed { ... }
-// other alignments are simply ignored. my tests show this is what llvm-gcc does too ...
-
-    //printf("\tAlignDeclaration::semantic '%s'\n",toChars());
-    if (decl)
-    {	unsigned salign_save = sc->structalign;
-
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-        if (s->isStructDeclaration() && salign == 1)
-        {
-            sc->structalign = salign;
-            s->semantic(sc);
-            sc->structalign = salign_save;
-        }
-        else
-        {
-            s->semantic(sc);
-        }
-	}
-	sc->structalign = salign_save;
-    }
-    else
-    assert(0 && "what kind of align use triggers this?");
-}
-
-
-void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->printf("align (%d)", salign);
-    AttribDeclaration::toCBuffer(buf, hgs);
-}
-
-/********************************* AnonDeclaration ****************************/
-
-AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl)
-	: AttribDeclaration(decl)
-{
-    this->loc = loc;
-    this->isunion = isunion;
-    this->scope = NULL;
-    this->sem = 0;
-}
-
-Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
-{
-    AnonDeclaration *ad;
-
-    assert(!s);
-    ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
-    return ad;
-}
-
-void AnonDeclaration::semantic(Scope *sc)
-{
-    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
-
-    Scope *scx = NULL;
-    if (scope)
-    {   sc = scope;
-	scx = scope;
-	scope = NULL;
-    }
-
-    assert(sc->parent);
-
-    Dsymbol *parent = sc->parent->pastMixin();
-    AggregateDeclaration *ad = parent->isAggregateDeclaration();
-
-    if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration()))
-    {
-	error("can only be a part of an aggregate");
-	return;
-    }
-
-    if (decl)
-    {
-	AnonymousAggregateDeclaration aad;
-	int adisunion;
-
-	if (sc->anonAgg)
-	{   ad = sc->anonAgg;
-	    adisunion = sc->inunion;
-	}
-	else
-	    adisunion = ad->isUnionDeclaration() != NULL;
-
-//	printf("\tsc->anonAgg = %p\n", sc->anonAgg);
-//	printf("\tad  = %p\n", ad);
-//	printf("\taad = %p\n", &aad);
-
-	sc = sc->push();
-	sc->anonAgg = &aad;
-	sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls);
-	sc->inunion = isunion;
-	sc->offset = 0;
-	sc->flags = 0;
-	aad.structalign = sc->structalign;
-	aad.parent = ad;
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic(sc);
-	    if (isunion)
-		sc->offset = 0;
-	    if (aad.sizeok == 2)
-	    {
-		break;
-	    }
-	}
-	sc = sc->pop();
-
-	// If failed due to forward references, unwind and try again later
-	if (aad.sizeok == 2)
-	{
-	    ad->sizeok = 2;
-	    //printf("\tsetting ad->sizeok %p to 2\n", ad);
-	    if (!sc->anonAgg)
-	    {
-		scope = scx ? scx : new Scope(*sc);
-		scope->setNoFree();
-		scope->module->addDeferredSemantic(this);
-	    }
-	    //printf("\tforward reference %p\n", this);
-	    return;
-	}
-	if (sem == 0)
-	{   Module::dprogress++;
-	    sem = 1;
-	    //printf("\tcompleted %p\n", this);
-	}
-	else
-	    ;//printf("\talready completed %p\n", this);
-
-	// 0 sized structs are set to 1 byte
-	if (aad.structsize == 0)
-	{
-	    aad.structsize = 1;
-	    aad.alignsize = 1;
-	}
-
-	// Align size of anonymous aggregate
-//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset);
-	ad->alignmember(aad.structalign, aad.alignsize, &sc->offset);
-	//ad->structsize = sc->offset;
-//printf("sc->offset = %d\n", sc->offset);
-
-	// Add members of aad to ad
-	//printf("\tadding members of aad (%p) to '%s'\n", &aad, ad->toChars());
-	for (unsigned i = 0; i < aad.fields.dim; i++)
-	{
-	    VarDeclaration *v = (VarDeclaration *)aad.fields.data[i];
-
-        // LDC
-        v->offset2 = sc->offset;
-
-	    v->offset += sc->offset;
-
-        // LDC
-        if (!v->anonDecl)
-            v->anonDecl = this;
-
-	    ad->fields.push(v);
-	}
-
-	// Add size of aad to ad
-	if (adisunion)
-	{
-	    if (aad.structsize > ad->structsize)
-		ad->structsize = aad.structsize;
-	    sc->offset = 0;
-	}
-	else
-	{
-	    ad->structsize = sc->offset + aad.structsize;
-	    sc->offset = ad->structsize;
-	}
-
-	if (ad->alignsize < aad.alignsize)
-	    ad->alignsize = aad.alignsize;
-    }
-}
-
-
-void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->printf(isunion ? "union" : "struct");
-    buf->writestring("\n{\n");
-    if (decl)
-    {
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    //buf->writestring("    ");
-	    s->toCBuffer(buf, hgs);
-	}
-    }
-    buf->writestring("}\n");
-}
-
-const char *AnonDeclaration::kind()
-{
-    return (isunion ? "anonymous union" : "anonymous struct");
-}
-
-/********************************* PragmaDeclaration ****************************/
-
-static bool parseStringExp(Expression* e, std::string& res)
-{
-    StringExp *s = NULL;
-
-    e = e->optimize(WANTvalue);
-    if (e->op == TOKstring && (s = (StringExp *)e))
-    {
-        char* str = (char*)s->string;
-        res = str;
-        return true;
-    }
-    return false;
-}
-
-PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl)
-	: AttribDeclaration(decl)
-{
-    this->loc = loc;
-    this->ident = ident;
-    this->args = args;
-}
-
-Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
-{
-    PragmaDeclaration *pd;
-
-    assert(!s);
-    pd = new PragmaDeclaration(loc, ident,
-	Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl));
-    return pd;
-}
-
-void PragmaDeclaration::semantic(Scope *sc)
-{   // Should be merged with PragmaStatement
-
-#if IN_LLVM
-    int llvm_internal = 0;
-    std::string arg1str;
-
-#endif
-
-    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
-    if (ident == Id::msg)
-    {
-	if (args)
-	{
-	    for (size_t i = 0; i < args->dim; i++)
-	    {
-		Expression *e = (Expression *)args->data[i];
-
-		e = e->semantic(sc);
-		e = e->optimize(WANTvalue | WANTinterpret);
-		if (e->op == TOKstring)
-		{
-		    StringExp *se = (StringExp *)e;
-		    fprintf(stdmsg, "%.*s", (int)se->len, se->string);
-		}
-		else
-		    error("string expected for message, not '%s'", e->toChars());
-	    }
-	    fprintf(stdmsg, "\n");
-	}
-	goto Lnodecl;
-    }
-    else if (ident == Id::lib)
-    {
-	if (!args || args->dim != 1)
-	    error("string expected for library name");
-	else
-	{
-	    Expression *e = (Expression *)args->data[0];
-
-	    e = e->semantic(sc);
-	    e = e->optimize(WANTvalue | WANTinterpret);
-	    args->data[0] = (void *)e;
-	    if (e->op != TOKstring)
-		error("string expected for library name, not '%s'", e->toChars());
-	    else if (global.params.verbose)
-	    {
-		StringExp *se = (StringExp *)e;
-		char *name = (char *)mem.malloc(se->len + 1);
-		memcpy(name, se->string, se->len);
-		name[se->len] = 0;
-		printf("library   %s\n", name);
-		mem.free(name);
-	    }
-	}
-	goto Lnodecl;
-    }
-#if IN_GCC
-    else if (ident == Id::GNU_asm)
-    {
-	if (! args || args->dim != 2)
-	    error("identifier and string expected for asm name");
-	else
-	{
-	    Expression *e;
-	    Declaration *d = NULL;
-	    StringExp *s = NULL;
-
-	    e = (Expression *)args->data[0];
-	    e = e->semantic(sc);
-	    if (e->op == TOKvar)
-	    {
-		d = ((VarExp *)e)->var;
-		if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
-		    d = NULL;
-	    }
-	    if (!d)
-		error("first argument of GNU_asm must be a function or variable declaration");
-
-	    e = (Expression *)args->data[1];
-	    e = e->semantic(sc);
-	    e = e->optimize(WANTvalue);
-	    if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
-		s = ((StringExp *)e);
-	    else
-		error("second argument of GNU_asm must be a char string");
-
-	    if (d && s)
-		d->c_ident = Lexer::idPool((char*) s->string);
-	}
-	goto Lnodecl;
-    }
-#endif
-    else if (ident == Id::startaddress)
-    {
-	if (!args || args->dim != 1)
-	    error("function name expected for start address");
-	else
-	{
-	    Expression *e = (Expression *)args->data[0];
-	    e = e->semantic(sc);
-	    e = e->optimize(WANTvalue | WANTinterpret);
-	    args->data[0] = (void *)e;
-	    Dsymbol *sa = getDsymbol(e);
-	    if (!sa || !sa->isFuncDeclaration())
-		error("function name expected for start address, not '%s'", e->toChars());
-	}
-	goto Lnodecl;
-    }
-
-    /////////////////////////////////////////////////////////////
-    /////////////////////////////////////////////////////////////
-    // LDC
-#if IN_LLVM
-
-    // pragma(intrinsic, "string") { funcdecl(s) }
-    else if (ident == Id::intrinsic)
-    {
-        Expression* expr = (Expression *)args->data[0];
-        expr = expr->semantic(sc);
-        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
-        {
-             error("requires exactly 1 string literal parameter");
-             fatal();
-        }
-        llvm_internal = LLVMintrinsic;
-    }
-
-    // pragma(notypeinfo) { typedecl(s) }
-    else if (ident == Id::no_typeinfo)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMno_typeinfo;
-    }
-
-    // pragma(nomoduleinfo) ;
-    else if (ident == Id::no_moduleinfo)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMno_moduleinfo;
-    }
-
-    // pragma(alloca) { funcdecl(s) }
-    else if (ident == Id::Alloca)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMalloca;
-    }
-
-    // pragma(va_start) { templdecl(s) }
-    else if (ident == Id::vastart)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMva_start;
-    }
-
-    // pragma(va_copy) { funcdecl(s) }
-    else if (ident == Id::vacopy)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMva_copy;
-    }
-
-    // pragma(va_end) { funcdecl(s) }
-    else if (ident == Id::vaend)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMva_end;
-    }
-
-    // pragma(va_arg) { templdecl(s) }
-    else if (ident == Id::vaarg)
-    {
-        if (args && args->dim > 0)
-        {
-             error("takes no parameters");
-             fatal();
-        }
-        llvm_internal = LLVMva_arg;
-    }
-    
-    // pragma(ldc, "string") { templdecl(s) }
-    else if (ident == Id::ldc)
-    {
-        Expression* expr = (Expression *)args->data[0];
-        expr = expr->semantic(sc);
-        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
-        {
-             error("requires exactly 1 string literal parameter");
-             fatal();
-        }
-        else if (arg1str == "verbose")
-        {
-            sc->module->llvmForceLogging = true;
-        }
-        else
-        {
-            error("command '%s' invalid");
-            fatal();
-        }
-    }
-
-#endif
-    // LDC
-    /////////////////////////////////////////////////////////////
-    /////////////////////////////////////////////////////////////
-
-    else if (ignoreUnsupportedPragmas)
-    {
-	if (global.params.verbose)
-	{
-	    /* Print unrecognized pragmas
-	     */
-	    printf("pragma    %s", ident->toChars());
-	    if (args)
-	    {
-		for (size_t i = 0; i < args->dim; i++)
-		{
-		    Expression *e = (Expression *)args->data[i];
-		    e = e->semantic(sc);
-		    e = e->optimize(WANTvalue | WANTinterpret);
-		    if (i == 0)
-			printf(" (");
-		    else
-			printf(",");
-		    printf("%s", e->toChars());
-		}
-		if (args->dim)
-		    printf(")");
-	    }
-	    printf("\n");
-	}
-	goto Lnodecl;
-    }
-    else
-	error("unrecognized pragma(%s)", ident->toChars());
-
-    if (decl)
-    {
-	for (unsigned i = 0; i < decl->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)decl->data[i];
-
-	    s->semantic(sc);
-
-// LDC
-#if IN_LLVM
-
-        if (llvm_internal)
-        {
-        if (s->llvmInternal)
-        {
-            error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars());
-            fatal();
-        }
-        switch(llvm_internal)
-        {
-        case LLVMintrinsic:
-            if (FuncDeclaration* fd = s->isFuncDeclaration())
-            {
-                fd->llvmInternal = llvm_internal;
-                fd->intrinsicName = arg1str;
-                fd->linkage = LINKintrinsic;
-                ((TypeFunction*)fd->type)->linkage = LINKintrinsic;
-            }
-            else if (TemplateDeclaration* td = s->isTemplateDeclaration())
-            {
-                td->llvmInternal = llvm_internal;
-                td->intrinsicName = arg1str;
-            }
-            else
-            {
-                error("only allowed on function declarations");
-                fatal();
-            }
-            break;
-
-        case LLVMva_start:
-        case LLVMva_arg:
-            if (TemplateDeclaration* td = s->isTemplateDeclaration())
-            {
-                if (td->parameters->dim != 1)
-                {
-                    error("the '%s' pragma template must have exactly one template parameter", ident->toChars());
-                    fatal();
-                }
-                else if (!td->onemember)
-                {
-                    error("the '%s' pragma template must have exactly one member", ident->toChars());
-                    fatal();
-                }
-                else if (td->overnext || td->overroot)
-                {
-                    error("the '%s' pragma template must not be overloaded", ident->toChars());
-                    fatal();
-                }
-                td->llvmInternal = llvm_internal;
-            }
-            else
-            {
-                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
-                fatal();
-            }
-            break;
-
-        case LLVMva_copy:
-        case LLVMva_end:
-            if (FuncDeclaration* fd = s->isFuncDeclaration())
-            {
-                fd->llvmInternal = llvm_internal;
-            }
-            else
-            {
-                error("the '%s' pragma is only allowed on function declarations", ident->toChars());
-                fatal();
-            }
-            break;
-
-        case LLVMno_typeinfo:
-            s->llvmInternal = llvm_internal;
-            break;
-
-        case LLVMalloca:
-            if (FuncDeclaration* fd = s->isFuncDeclaration())
-            {
-                fd->llvmInternal = llvm_internal;
-            }
-            else
-            {
-                error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars());
-                fatal();
-            }
-            break;
-
-        default:
-            warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
-        }
-        }
-
-#endif // LDC
-
-    }
-    }
-    return;
-
-Lnodecl:
-    if (decl)
-	error("pragma is missing closing ';'");
-}
-
-int PragmaDeclaration::oneMember(Dsymbol **ps)
-{
-    *ps = NULL;
-    return TRUE;
-}
-
-const char *PragmaDeclaration::kind()
-{
-    return "pragma";
-}
-
-void PragmaDeclaration::toObjFile(int multiobj)
-{
-    if (ident == Id::lib)
-    {
-	assert(args && args->dim == 1);
-
-	Expression *e = (Expression *)args->data[0];
-
-	assert(e->op == TOKstring);
-
-	StringExp *se = (StringExp *)e;
-	char *name = (char *)mem.malloc(se->len + 1);
-	memcpy(name, se->string, se->len);
-	name[se->len] = 0;
-	obj_includelib(name);
-    }
-    else if (ident == Id::startaddress)
-    {
-	assert(args && args->dim == 1);
-	Expression *e = (Expression *)args->data[0];
-	Dsymbol *sa = getDsymbol(e);
-	FuncDeclaration *f = sa->isFuncDeclaration();
-	assert(f);
-	Symbol *s = f->toSymbol();
-    assert(0 && "startaddress pragma not implemented");
-// 	obj_startaddress(s);
-    }
-    AttribDeclaration::toObjFile(multiobj);
-}
-
-void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->printf("pragma (%s", ident->toChars());
-    if (args && args->dim)
-    {
-        buf->writestring(", ");
-        argsToCBuffer(buf, args, hgs);
-    }
-    buf->writeByte(')');
-    AttribDeclaration::toCBuffer(buf, hgs);
-}
-
-
-/********************************* ConditionalDeclaration ****************************/
-
-ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl)
-	: AttribDeclaration(decl)
-{
-    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
-    this->condition = condition;
-    this->elsedecl = elsedecl;
-}
-
-Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
-{
-    ConditionalDeclaration *dd;
-
-    assert(!s);
-    dd = new ConditionalDeclaration(condition->syntaxCopy(),
-	Dsymbol::arraySyntaxCopy(decl),
-	Dsymbol::arraySyntaxCopy(elsedecl));
-    return dd;
-}
-
-
-int ConditionalDeclaration::oneMember(Dsymbol **ps)
-{
-    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
-    if (condition->inc)
-    {
-	Array *d = condition->include(NULL, NULL) ? decl : elsedecl;
-	return Dsymbol::oneMembers(d, ps);
-    }
-    *ps = NULL;
-    return TRUE;
-}
-
-void ConditionalDeclaration::emitComment(Scope *sc)
-{
-    //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
-    if (condition->inc)
-    {
-	AttribDeclaration::emitComment(sc);
-    }
-}
-
-// Decide if 'then' or 'else' code should be included
-
-Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd)
-{
-    //printf("ConditionalDeclaration::include()\n");
-    assert(condition);
-    return condition->include(sc, sd) ? decl : elsedecl;
-}
-
-
-void ConditionalDeclaration::addComment(unsigned char *comment)
-{
-    /* Because addComment is called by the parser, if we called
-     * include() it would define a version before it was used.
-     * But it's no problem to drill down to both decl and elsedecl,
-     * so that's the workaround.
-     */
-
-    if (comment)
-    {
-	Array *d = decl;
-
-	for (int j = 0; j < 2; j++)
-	{
-	    if (d)
-	    {
-		for (unsigned i = 0; i < d->dim; i++)
-		{   Dsymbol *s;
-
-		    s = (Dsymbol *)d->data[i];
-		    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
-		    s->addComment(comment);
-		}
-	    }
-	    d = elsedecl;
-	}
-    }
-}
-
-void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    condition->toCBuffer(buf, hgs);
-    if (decl || elsedecl)
-    {
-	buf->writenl();
-	buf->writeByte('{');
-	buf->writenl();
-	if (decl)
-	{
-	    for (unsigned i = 0; i < decl->dim; i++)
-	    {
-		Dsymbol *s = (Dsymbol *)decl->data[i];
-
-		buf->writestring("    ");
-		s->toCBuffer(buf, hgs);
-	    }
-	}
-	buf->writeByte('}');
-	if (elsedecl)
-	{
-	    buf->writenl();
-	    buf->writestring("else");
-	    buf->writenl();
-	    buf->writeByte('{');
-	    buf->writenl();
-	    for (unsigned i = 0; i < elsedecl->dim; i++)
-	    {
-		Dsymbol *s = (Dsymbol *)elsedecl->data[i];
-
-		buf->writestring("    ");
-		s->toCBuffer(buf, hgs);
-	    }
-	    buf->writeByte('}');
-	}
-    }
-    else
-	buf->writeByte(':');
-    buf->writenl();
-}
-
-/***************************** StaticIfDeclaration ****************************/
-
-StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
-	Array *decl, Array *elsedecl)
-	: ConditionalDeclaration(condition, decl, elsedecl)
-{
-    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
-    sd = NULL;
-    addisdone = 0;
-}
-
-
-Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
-{
-    StaticIfDeclaration *dd;
-
-    assert(!s);
-    dd = new StaticIfDeclaration(condition->syntaxCopy(),
-	Dsymbol::arraySyntaxCopy(decl),
-	Dsymbol::arraySyntaxCopy(elsedecl));
-    return dd;
-}
-
-
-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:
-     *
-     * template Foo(int i)
-     * {
-     *     const int j = i + 1;
-     *     static if (j == 3)
-     *         const int k;
-     * }
-     */
-    this->sd = sd;
-    int m = 0;
-
-    if (memnum == 0)
-    {	m = AttribDeclaration::addMember(sc, sd, memnum);
-	addisdone = 1;
-    }
-    return m;
-}
-
-
-void StaticIfDeclaration::semantic(Scope *sc)
-{
-    Array *d = include(sc, sd);
-
-    //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d);
-    if (d)
-    {
-	if (!addisdone)
-	{   AttribDeclaration::addMember(sc, sd, 1);
-	    addisdone = 1;
-	}
-
-	for (unsigned i = 0; i < d->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)d->data[i];
-
-	    s->semantic(sc);
-	}
-    }
-}
-
-const char *StaticIfDeclaration::kind()
-{
-    return "static if";
-}
-
-
-/***************************** CompileDeclaration *****************************/
-
-CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
-    : AttribDeclaration(NULL)
-{
-    //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
-    this->loc = loc;
-    this->exp = exp;
-    this->sd = NULL;
-    this->compiled = 0;
-}
-
-Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
-{
-    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
-    CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy());
-    return sc;
-}
-
-int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
-{
-    //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum);
-    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(loc = %d)\n", loc.linnum);
-    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");
-
-    if (!compiled)
-    {
-	compileIt(sc);
-	AttribDeclaration::addMember(sc, sd, 0);
-	compiled = 1;
-    }
-    AttribDeclaration::semantic(sc);
-}
-
-void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("mixin(");
-    exp->toCBuffer(buf, hgs);
-    buf->writestring(");");
-    buf->writenl();
-}
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2009 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 "rmem.h"
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "cond.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "module.h"
+#include "parse.h"
+#include "template.h"
+
+#if IN_LLVM
+#include "../gen/enums.h"
+
+#include "llvm/Support/CommandLine.h"
+
+static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore",
+    llvm::cl::desc("Ignore unsupported pragmas"),
+    llvm::cl::ZeroOrMore);
+
+#endif
+
+
+extern void obj_includelib(const char *name);
+
+#if IN_DMD
+void obj_startaddress(Symbol *s);
+#endif
+
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Array *decl)
+	: Dsymbol()
+{
+    this->decl = decl;
+}
+
+Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    return decl;
+}
+
+int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    int m = 0;
+    Array *d = include(sc, sd);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    m |= s->addMember(sc, sd, m | memnum);
+	}
+    }
+    return m;
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->semantic2(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->semantic3(sc);
+	}
+    }
+}
+
+void AttribDeclaration::inlineScan()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
+	    s->inlineScan();
+	}
+    }
+}
+
+void AttribDeclaration::addComment(unsigned char *comment)
+{
+    if (comment)
+    {
+	Array *d = include(NULL, NULL);
+
+	if (d)
+	{
+	    for (unsigned i = 0; i < d->dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)d->data[i];
+		//printf("AttribDeclaration::addComment %s\n", s->toChars());
+		s->addComment(comment);
+	    }
+	}
+    }
+}
+
+void AttribDeclaration::emitComment(Scope *sc)
+{
+    //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+    /* A general problem with this, illustrated by BUGZILLA 2516,
+     * is that attributes are not transmitted through to the underlying
+     * member declarations for template bodies, because semantic analysis
+     * is not done for template declaration bodies
+     * (only template instantiations).
+     * Hence, Ddoc omits attributes from template members.
+     */
+
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+	    s->emitComment(sc);
+	}
+    }
+}
+
+#if IN_DMD
+
+void AttribDeclaration::toObjFile(int multiobj)
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->toObjFile(multiobj);
+	}
+    }
+}
+
+int AttribDeclaration::cvMember(unsigned char *p)
+{
+    int nwritten = 0;
+    int n;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    n = s->cvMember(p);
+	    if (p)
+		p += n;
+	    nwritten += n;
+	}
+    }
+    return nwritten;
+}
+#endif
+
+int AttribDeclaration::hasPointers()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (size_t i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+	    if (s->hasPointers())
+		return 1;
+	}
+    }
+    return 0;
+}
+
+const char *AttribDeclaration::kind()
+{
+    return "attribute";
+}
+
+int AttribDeclaration::oneMember(Dsymbol **ps)
+{
+    Array *d = include(NULL, NULL);
+
+    return Dsymbol::oneMembers(d, ps);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->checkCtorConstInit();
+	}
+    }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->addLocalClass(aclasses);
+	}
+    }
+}
+
+
+void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (decl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writeByte('}');
+    }
+    else
+	buf->writeByte(';');
+    buf->writenl();
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StorageClassDeclaration *scd;
+
+    assert(!s);
+    scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+    return scd;
+}
+
+void StorageClassDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	unsigned stc_save = sc->stc;
+
+	if (stc & (STCauto | STCscope | STCstatic | STCextern))
+	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern);
+	sc->stc |= stc;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->stc = stc_save;
+    }
+    else
+	sc->stc = stc;
+}
+
+void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, int stc)
+{
+    struct SCstring
+    {
+	int stc;
+	enum TOK tok;
+    };
+
+    static SCstring table[] =
+    {
+	{ STCauto,         TOKauto },
+	{ STCscope,        TOKscope },
+	{ STCstatic,       TOKstatic },
+	{ STCextern,       TOKextern },
+	{ STCconst,        TOKconst },
+	{ STCimmutable,    TOKimmutable },
+	{ STCshared,       TOKshared },
+	{ STCfinal,        TOKfinal },
+	{ STCabstract,     TOKabstract },
+	{ STCsynchronized, TOKsynchronized },
+	{ STCdeprecated,   TOKdeprecated },
+	{ STCoverride,     TOKoverride },
+	{ STCnothrow,      TOKnothrow },
+	{ STCpure,         TOKpure },
+	{ STCref,          TOKref },
+	{ STCtls,          TOKtls },
+	{ STCgshared,      TOKgshared },
+	{ STClazy,         TOKlazy },
+	{ STCalias,        TOKalias },
+	{ STCout,          TOKout },
+	{ STCin,           TOKin },
+    };
+
+    for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
+    {
+	if (stc & table[i].stc)
+	{
+	    buf->writestring(Token::toChars(table[i].tok));
+	    buf->writeByte(' ');
+	}
+    }
+}
+
+void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    stcToCBuffer(buf, stc);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+    linkage = p;
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+    LinkDeclaration *ld;
+
+    assert(!s);
+    ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+    return ld;
+}
+
+void LinkDeclaration::semantic(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::semantic3(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic3(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   const char *p;
+
+    switch (linkage)
+    {
+	case LINKd:		p = "D";		break;
+	case LINKc:		p = "C";		break;
+	case LINKcpp:		p = "C++";		break;
+	case LINKwindows:	p = "Windows";		break;
+	case LINKpascal:	p = "Pascal";		break;
+
+#if IN_LLVM
+    case LINKintrinsic: p = "Intrinsic"; break;
+#endif
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring("extern (");
+    buf->writestring(p);
+    buf->writestring(") ");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+char *LinkDeclaration::toChars()
+{
+    return (char *)"extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    protection = p;
+    //printf("decl = %p\n", decl);
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ProtDeclaration *pd;
+
+    assert(!s);
+    pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void ProtDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	enum PROT protection_save = sc->protection;
+	int explicitProtection_save = sc->explicitProtection;
+
+	sc->protection = protection;
+	sc->explicitProtection = 1;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->protection = protection_save;
+	sc->explicitProtection = explicitProtection_save;
+    }
+    else
+    {	sc->protection = protection;
+	sc->explicitProtection = 1;
+    }
+}
+
+void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   const char *p;
+
+    switch (protection)
+    {
+	case PROTprivate:	p = "private";		break;
+	case PROTpackage:	p = "package";		break;
+	case PROTprotected:	p = "protected";	break;
+	case PROTpublic:	p = "public";		break;
+	case PROTexport:	p = "export";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring(p);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    salign = sa;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AlignDeclaration *ad;
+
+    assert(!s);
+    ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AlignDeclaration::semantic(Scope *sc)
+{
+// LDC
+// we only support packed structs, as from the spec: align(1) struct Packed { ... }
+// other alignments are simply ignored. my tests show this is what llvm-gcc does too ...
+
+    //printf("\tAlignDeclaration::semantic '%s'\n",toChars());
+    if (decl)
+    {	unsigned salign_save = sc->structalign;
+#if IN_DMD
+	sc->structalign = salign;
+#endif
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+        if (s->isStructDeclaration() && salign == 1)
+        {
+            sc->structalign = salign;
+            s->semantic(sc);
+            sc->structalign = salign_save;
+        }
+        else
+        {
+            s->semantic(sc);
+        }
+	}
+	sc->structalign = salign_save;
+    }
+    else
+    assert(0 && "what kind of align use triggers this?");
+}
+
+
+void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("align (%d)", salign);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->isunion = isunion;
+    this->scope = NULL;
+    this->sem = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AnonDeclaration *ad;
+
+    assert(!s);
+    ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+    Scope *scx = NULL;
+    if (scope)
+    {   sc = scope;
+	scx = scope;
+	scope = NULL;
+    }
+
+    assert(sc->parent);
+
+    Dsymbol *parent = sc->parent->pastMixin();
+    AggregateDeclaration *ad = parent->isAggregateDeclaration();
+
+    if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration()))
+    {
+	error("can only be a part of an aggregate");
+	return;
+    }
+
+    if (decl)
+    {
+	AnonymousAggregateDeclaration aad;
+	int adisunion;
+
+	if (sc->anonAgg)
+	{   ad = sc->anonAgg;
+	    adisunion = sc->inunion;
+	}
+	else
+	    adisunion = ad->isUnionDeclaration() != NULL;
+
+//	printf("\tsc->anonAgg = %p\n", sc->anonAgg);
+//	printf("\tad  = %p\n", ad);
+//	printf("\taad = %p\n", &aad);
+
+	sc = sc->push();
+	sc->anonAgg = &aad;
+	sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
+	sc->inunion = isunion;
+	sc->offset = 0;
+	sc->flags = 0;
+	aad.structalign = sc->structalign;
+	aad.parent = ad;
+
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	    if (isunion)
+		sc->offset = 0;
+	    if (aad.sizeok == 2)
+	    {
+		break;
+	    }
+	}
+	sc = sc->pop();
+
+	// If failed due to forward references, unwind and try again later
+	if (aad.sizeok == 2)
+	{
+	    ad->sizeok = 2;
+	    //printf("\tsetting ad->sizeok %p to 2\n", ad);
+	    if (!sc->anonAgg)
+	    {
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    //printf("\tforward reference %p\n", this);
+	    return;
+	}
+	if (sem == 0)
+	{   Module::dprogress++;
+	    sem = 1;
+	    //printf("\tcompleted %p\n", this);
+	}
+	else
+	    ;//printf("\talready completed %p\n", this);
+
+	// 0 sized structs are set to 1 byte
+	if (aad.structsize == 0)
+	{
+	    aad.structsize = 1;
+	    aad.alignsize = 1;
+	}
+
+	// Align size of anonymous aggregate
+//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset);
+	ad->alignmember(aad.structalign, aad.alignsize, &sc->offset);
+	//ad->structsize = sc->offset;
+//printf("sc->offset = %d\n", sc->offset);
+
+	// Add members of aad to ad
+	//printf("\tadding members of aad to '%s'\n", ad->toChars());
+	for (unsigned i = 0; i < aad.fields.dim; i++)
+	{
+	    VarDeclaration *v = (VarDeclaration *)aad.fields.data[i];
+
+#if IN_LLVM
+        v->offset2 = sc->offset;
+#endif
+	    v->offset += sc->offset;
+
+#if IN_LLVM
+        if (!v->anonDecl)
+            v->anonDecl = this;
+#endif
+	    ad->fields.push(v);
+	}
+
+	// Add size of aad to ad
+	if (adisunion)
+	{
+	    if (aad.structsize > ad->structsize)
+		ad->structsize = aad.structsize;
+	    sc->offset = 0;
+	}
+	else
+	{
+	    ad->structsize = sc->offset + aad.structsize;
+	    sc->offset = ad->structsize;
+	}
+
+	if (ad->alignsize < aad.alignsize)
+	    ad->alignsize = aad.alignsize;
+    }
+}
+
+
+void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf(isunion ? "union" : "struct");
+    buf->writestring("\n{\n");
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    //buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring("}\n");
+}
+
+const char *AnonDeclaration::kind()
+{
+    return (isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+static bool parseStringExp(Expression* e, std::string& res)
+{
+    StringExp *s = NULL;
+
+    e = e->optimize(WANTvalue);
+    if (e->op == TOKstring && (s = (StringExp *)e))
+    {
+        char* str = (char*)s->string;
+        res = str;
+        return true;
+    }
+    return false;
+}
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
+    PragmaDeclaration *pd;
+
+    assert(!s);
+    pd = new PragmaDeclaration(loc, ident,
+	Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{   // Should be merged with PragmaStatement
+
+#if IN_LLVM
+    int llvm_internal = 0;
+    std::string arg1str;
+#endif
+
+    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+    if (ident == Id::msg)
+    {
+	if (args)
+	{
+	    for (size_t i = 0; i < args->dim; i++)
+	    {
+		Expression *e = (Expression *)args->data[i];
+
+		e = e->semantic(sc);
+		e = e->optimize(WANTvalue | WANTinterpret);
+		if (e->op == TOKstring)
+		{
+		    StringExp *se = (StringExp *)e;
+		    fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string);
+		}
+		else
+		    error("string expected for message, not '%s'", e->toChars());
+	    }
+	    fprintf(stdmsg, "\n");
+	}
+	goto Lnodecl;
+    }
+    else if (ident == Id::lib)
+    {
+	if (!args || args->dim != 1)
+	    error("string expected for library name");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    if (e->op != TOKstring)
+		error("string expected for library name, not '%s'", e->toChars());
+	    else if (global.params.verbose)
+	    {
+		StringExp *se = (StringExp *)e;
+		char *name = (char *)mem.malloc(se->len + 1);
+		memcpy(name, se->string, se->len);
+		name[se->len] = 0;
+		printf("library   %s\n", name);
+		mem.free(name);
+	    }
+	}
+	goto Lnodecl;
+    }
+#if IN_GCC
+    else if (ident == Id::GNU_asm)
+    {
+	if (! args || args->dim != 2)
+	    error("identifier and string expected for asm name");
+	else
+	{
+	    Expression *e;
+	    Declaration *d = NULL;
+	    StringExp *s = NULL;
+
+	    e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    if (e->op == TOKvar)
+	    {
+		d = ((VarExp *)e)->var;
+		if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
+		    d = NULL;
+	    }
+	    if (!d)
+		error("first argument of GNU_asm must be a function or variable declaration");
+
+	    e = (Expression *)args->data[1];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue);
+	    if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
+		s = ((StringExp *)e);
+	    else
+		error("second argument of GNU_asm must be a char string");
+
+	    if (d && s)
+		d->c_ident = Lexer::idPool((char*) s->string);
+	}
+	goto Lnodecl;
+    }
+#endif
+    else if (ident == Id::startaddress)
+    {
+	if (!args || args->dim != 1)
+	    error("function name expected for start address");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    Dsymbol *sa = getDsymbol(e);
+	    if (!sa || !sa->isFuncDeclaration())
+		error("function name expected for start address, not '%s'", e->toChars());
+	}
+	goto Lnodecl;
+    }
+
+// LDC
+#if IN_LLVM
+
+    // pragma(intrinsic, "string") { funcdecl(s) }
+    else if (ident == Id::intrinsic)
+    {
+        Expression* expr = (Expression *)args->data[0];
+        expr = expr->semantic(sc);
+        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
+        {
+             error("requires exactly 1 string literal parameter");
+             fatal();
+        }
+        llvm_internal = LLVMintrinsic;
+    }
+
+    // pragma(notypeinfo) { typedecl(s) }
+    else if (ident == Id::no_typeinfo)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMno_typeinfo;
+    }
+
+    // pragma(nomoduleinfo) ;
+    else if (ident == Id::no_moduleinfo)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMno_moduleinfo;
+    }
+
+    // pragma(alloca) { funcdecl(s) }
+    else if (ident == Id::Alloca)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMalloca;
+    }
+
+    // pragma(va_start) { templdecl(s) }
+    else if (ident == Id::vastart)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_start;
+    }
+
+    // pragma(va_copy) { funcdecl(s) }
+    else if (ident == Id::vacopy)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_copy;
+    }
+
+    // pragma(va_end) { funcdecl(s) }
+    else if (ident == Id::vaend)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_end;
+    }
+
+    // pragma(va_arg) { templdecl(s) }
+    else if (ident == Id::vaarg)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_arg;
+    }
+    
+    // pragma(ldc, "string") { templdecl(s) }
+    else if (ident == Id::ldc)
+    {
+        Expression* expr = (Expression *)args->data[0];
+        expr = expr->semantic(sc);
+        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
+        {
+             error("requires exactly 1 string literal parameter");
+             fatal();
+        }
+        else if (arg1str == "verbose")
+        {
+            sc->module->llvmForceLogging = true;
+        }
+        else
+        {
+            error("command '%s' invalid", expr->toChars());
+            fatal();
+        }
+    }
+
+    // pragma(llvm_inline_asm) { templdecl(s) }
+    else if (ident == Id::llvm_inline_asm)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMinline_asm;
+    }
+
+#endif // LDC
+
+    else if (ignoreUnsupportedPragmas)
+    {
+	if (global.params.verbose)
+	{
+	    /* Print unrecognized pragmas
+	     */
+	    printf("pragma    %s", ident->toChars());
+	    if (args)
+	    {
+		for (size_t i = 0; i < args->dim; i++)
+		{
+                    // ignore errors in ignored pragmas.
+                    global.gag++;
+                    unsigned errors_save = global.errors;
+
+		    Expression *e = (Expression *)args->data[i];
+		    e = e->semantic(sc);
+		    e = e->optimize(WANTvalue | WANTinterpret);
+		    if (i == 0)
+			printf(" (");
+		    else
+			printf(",");
+		    printf("%s", e->toChars());
+
+                    // restore error state.
+                    global.gag--;
+                    global.errors = errors_save;
+		}
+		if (args->dim)
+		    printf(")");
+	    }
+	    printf("\n");
+	}
+    }
+    else
+	error("unrecognized pragma(%s)", ident->toChars());
+
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+
+// LDC
+#if IN_LLVM
+
+        if (llvm_internal)
+        {
+        if (s->llvmInternal)
+        {
+            error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars());
+            fatal();
+        }
+        switch(llvm_internal)
+        {
+        case LLVMintrinsic:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+                fd->intrinsicName = arg1str;
+                fd->linkage = LINKintrinsic;
+                ((TypeFunction*)fd->type)->linkage = LINKintrinsic;
+            }
+            else if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                td->llvmInternal = llvm_internal;
+                td->intrinsicName = arg1str;
+            }
+            else
+            {
+                error("only allowed on function declarations");
+                fatal();
+            }
+            break;
+
+        case LLVMva_start:
+        case LLVMva_arg:
+            if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                if (td->parameters->dim != 1)
+                {
+                    error("the '%s' pragma template must have exactly one template parameter", ident->toChars());
+                    fatal();
+                }
+                else if (!td->onemember)
+                {
+                    error("the '%s' pragma template must have exactly one member", ident->toChars());
+                    fatal();
+                }
+                else if (td->overnext || td->overroot)
+                {
+                    error("the '%s' pragma template must not be overloaded", ident->toChars());
+                    fatal();
+                }
+                td->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
+                fatal();
+            }
+            break;
+
+        case LLVMva_copy:
+        case LLVMva_end:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma is only allowed on function declarations", ident->toChars());
+                fatal();
+            }
+            break;
+
+        case LLVMno_typeinfo:
+            s->llvmInternal = llvm_internal;
+            break;
+
+        case LLVMalloca:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars());
+                fatal();
+            }
+            break;
+
+        case LLVMinline_asm:
+            if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                if (td->parameters->dim > 1)
+                {
+                    error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars());
+                    fatal();
+                }
+                else if (!td->onemember)
+                {
+                    error("the '%s' pragma template must have exactly one member", ident->toChars());
+                    fatal();
+                }
+                td->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
+                fatal();
+            }
+            break;
+
+        default:
+            warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
+        }
+        }
+
+#endif // LDC
+
+    }
+    }
+    return;
+
+Lnodecl:
+    if (decl)
+	error("pragma is missing closing ';'");
+}
+
+int PragmaDeclaration::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+const char *PragmaDeclaration::kind()
+{
+    return "pragma";
+}
+
+#if IN_DMD
+void PragmaDeclaration::toObjFile(int multiobj)
+{
+    if (ident == Id::lib)
+    {
+	assert(args && args->dim == 1);
+
+	Expression *e = (Expression *)args->data[0];
+
+	assert(e->op == TOKstring);
+
+	StringExp *se = (StringExp *)e;
+	char *name = (char *)mem.malloc(se->len + 1);
+	memcpy(name, se->string, se->len);
+	name[se->len] = 0;
+#if OMFOBJ
+	/* The OMF format allows library names to be inserted
+	 * into the object file. The linker will then automatically
+	 * search that library, too.
+	 */
+	obj_includelib(name);
+#elif ELFOBJ || MACHOBJ
+	/* The format does not allow embedded library names,
+	 * so instead append the library name to the list to be passed
+	 * to the linker.
+	 */
+	global.params.libfiles->push((void *) name);
+#else
+	error("pragma lib not supported");
+#endif
+    }
+#if DMDV2
+    else if (ident == Id::startaddress)
+    {
+	assert(args && args->dim == 1);
+	Expression *e = (Expression *)args->data[0];
+	Dsymbol *sa = getDsymbol(e);
+	FuncDeclaration *f = sa->isFuncDeclaration();
+	assert(f);
+	Symbol *s = f->toSymbol();
+	obj_startaddress(s);
+    }
+#endif
+    AttribDeclaration::toObjFile(multiobj);
+}
+#endif
+
+void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("pragma (%s", ident->toChars());
+    if (args && args->dim)
+    {
+        buf->writestring(", ");
+        argsToCBuffer(buf, args, hgs);
+    }
+    buf->writeByte(')');
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl)
+	: AttribDeclaration(decl)
+{
+    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+    this->condition = condition;
+    this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ConditionalDeclaration *dd;
+
+    assert(!s);
+    dd = new ConditionalDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int ConditionalDeclaration::oneMember(Dsymbol **ps)
+{
+    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+    if (condition->inc)
+    {
+	Array *d = condition->include(NULL, NULL) ? decl : elsedecl;
+	return Dsymbol::oneMembers(d, ps);
+    }
+    *ps = NULL;
+    return TRUE;
+}
+
+void ConditionalDeclaration::emitComment(Scope *sc)
+{
+    //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+    if (condition->inc)
+    {
+	AttribDeclaration::emitComment(sc);
+    }
+    else if (sc->docbuf)
+    {
+	/* If generating doc comment, be careful because if we're inside
+	 * a template, then include(NULL, NULL) will fail.
+	 */
+	Array *d = decl ? decl : elsedecl;
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->emitComment(sc);
+	}
+    }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("ConditionalDeclaration::include()\n");
+    assert(condition);
+    return condition->include(sc, sd) ? decl : elsedecl;
+}
+
+
+void ConditionalDeclaration::addComment(unsigned char *comment)
+{
+    /* Because addComment is called by the parser, if we called
+     * include() it would define a version before it was used.
+     * But it's no problem to drill down to both decl and elsedecl,
+     * so that's the workaround.
+     */
+
+    if (comment)
+    {
+	Array *d = decl;
+
+	for (int j = 0; j < 2; j++)
+	{
+	    if (d)
+	    {
+		for (unsigned i = 0; i < d->dim; i++)
+		{   Dsymbol *s;
+
+		    s = (Dsymbol *)d->data[i];
+		    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+		    s->addComment(comment);
+		}
+	    }
+	    d = elsedecl;
+	}
+    }
+}
+
+void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    condition->toCBuffer(buf, hgs);
+    if (decl || elsedecl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	if (decl)
+	{
+	    for (unsigned i = 0; i < decl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)decl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	}
+	buf->writeByte('}');
+	if (elsedecl)
+	{
+	    buf->writenl();
+	    buf->writestring("else");
+	    buf->writenl();
+	    buf->writeByte('{');
+	    buf->writenl();
+	    for (unsigned i = 0; i < elsedecl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)elsedecl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	    buf->writeByte('}');
+	}
+    }
+    else
+	buf->writeByte(':');
+    buf->writenl();
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+	Array *decl, Array *elsedecl)
+	: ConditionalDeclaration(condition, decl, elsedecl)
+{
+    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+    sd = NULL;
+    addisdone = 0;
+}
+
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticIfDeclaration *dd;
+
+    assert(!s);
+    dd = new StaticIfDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+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:
+     *
+     * template Foo(int i)
+     * {
+     *     const int j = i + 1;
+     *     static if (j == 3)
+     *         const int k;
+     * }
+     */
+    this->sd = sd;
+    int m = 0;
+
+    if (memnum == 0)
+    {	m = AttribDeclaration::addMember(sc, sd, memnum);
+	addisdone = 1;
+    }
+    return m;
+}
+
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, sd);
+
+    //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+	if (!addisdone)
+	{   AttribDeclaration::addMember(sc, sd, 1);
+	    addisdone = 1;
+	}
+
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+const char *StaticIfDeclaration::kind()
+{
+    return "static if";
+}
+
+
+/***************************** CompileDeclaration *****************************/
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+    : AttribDeclaration(NULL)
+{
+    //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+    this->loc = loc;
+    this->exp = exp;
+    this->sd = NULL;
+    this->compiled = 0;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+    CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy());
+    return sc;
+}
+
+int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum);
+    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(loc = %d)\n", loc.linnum);
+    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");
+
+    if (!compiled)
+    {
+	compileIt(sc);
+	AttribDeclaration::addMember(sc, sd, 0);
+	compiled = 1;
+    }
+    AttribDeclaration::semantic(sc);
+}
+
+void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(");");
+    buf->writenl();
+}
--- a/dmd2/attrib.h	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/attrib.h	Sat May 30 17:23:32 2009 +0100
@@ -50,8 +50,14 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     AttribDeclaration *isAttribDeclaration() { return this; }
 
-    virtual void toObjFile(int multiobj);			// compile to .obj file
+#if IN_DMD
+    void toObjFile(int multiobj);			// compile to .obj file
     int cvMember(unsigned char *p);
+#endif
+
+#if IN_LLVM
+    virtual void codegen(Ir*);
+#endif
 };
 
 struct StorageClassDeclaration: AttribDeclaration
@@ -62,6 +68,8 @@
     Dsymbol *syntaxCopy(Dsymbol *s);
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    static void stcToCBuffer(OutBuffer *buf, int stc);
 };
 
 struct LinkDeclaration : AttribDeclaration
@@ -107,9 +115,6 @@
     void semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     const char *kind();
-
-    // LDC
-    void toObjFile(int multiobj);           // compile to .obj file
 };
 
 struct PragmaDeclaration : AttribDeclaration
@@ -122,7 +127,14 @@
     int oneMember(Dsymbol **ps);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     const char *kind();
+
+#if IN_DMD
     void toObjFile(int multiobj);			// compile to .obj file
+#endif
+
+#if IN_LLVM
+    void codegen(Ir*);
+#endif
 };
 
 struct ConditionalDeclaration : AttribDeclaration
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/backendlicense.txt	Sat May 30 17:23:32 2009 +0100
@@ -0,0 +1,42 @@
+
+The Software is not generally available software. It has not undergone
+testing and may contain errors. The Software was not designed to operate
+after December 31, 1999. It may be incomplete and it may not function
+properly. No support or maintenance is provided with this Software. Do
+not install or distribute the Software if
+you are not accustomed to using or distributing experimental software.
+Do not use this software for life critical applications, or applications
+that could cause significant harm or property damage.
+
+Digital Mars licenses the Software to you on an "AS IS" basis, without
+warranty of any kind. DIGITAL MARS AND SYMANTEC HEREBY EXPRESSLY DISCLAIM
+ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY,
+NONINFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. You are solely
+responsible for determining the appropriateness of using this Software and
+assume all risks associated with the use of this Software, including but not
+limited to the risks of program errors, damage
+to or loss of data, programs or equipment, unavailability or interruption of
+operations and third party claims. You agree to defend, indemnify and hold
+Digital Mars and Symantec, its subsidiaries, affiliates, directors, officers,
+employees and agents harmless from all claims or demands made against them
+(and any related losses, damages, expenses
+and costs) arising out of your use of the Software. DIGITAL MARS AND SYMANTEC
+WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, INCIDENTAL, OR
+INDIRECT DAMAGES OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES (INCLUDING
+LOST PROFITS OR SAVINGS), EVEN IF DIGITAL MARS OR SYMANTEC HAS BEEN ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGES.
+Digital Mars and Symantec will not be liable for the loss of, or damage to,
+your records or data, the records or
+data of any third party, or any damages claimed by you based on a third party
+claim.
+
+If you send any messages to Digital Mars, on either the Digital Mars
+newsgroups, the Digital Mars mailing list, or via email, you agree not
+to make any claims of intellectual
+property rights over the contents of those messages.
+
+The Software is copyrighted and comes with a single user license,
+and may not be redistributed. If you wish to obtain a redistribution license,
+please contact Digital Mars.
+
--- a/dmd2/builtin.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/builtin.c	Sat May 30 17:23:32 2009 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
+// Copyright (c) 1999-2009 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -23,12 +23,15 @@
 #include "id.h"
 #include "module.h"
 
+#if DMDV2
+
 /**********************************
- * Determine if function is a builtin one.
+ * Determine if function is a builtin one that we can
+ * evaluate at compile time.
  */
 enum BUILTIN FuncDeclaration::isBuiltin()
 {
-    static const char FeZe[] = "FeZe";	// real function(real)
+    static const char FeZe[] = "FNaNbeZe";	// pure nothrow real function(real)
 
     //printf("FuncDeclaration::isBuiltin() %s\n", toChars());
     if (builtin == BUILTINunknown)
@@ -36,10 +39,12 @@
 	builtin = BUILTINnot;
 	if (parent && parent->isModule())
 	{
+	    // If it's in the std.math package
 	    if (parent->ident == Id::math &&
 		parent->parent && parent->parent->ident == Id::std &&
 		!parent->parent->parent)
 	    {
+		//printf("deco = %s\n", type->deco);
 		if (strcmp(type->deco, FeZe) == 0)
 		{
 		    if (ident == Id::sin)
@@ -54,6 +59,13 @@
 			builtin = BUILTINfabs;
 		    //printf("builtin = %d\n", builtin);
 		}
+		// if float or double versions
+		else if (strcmp(type->deco, "FNaNbdZd") == 0 ||
+			 strcmp(type->deco, "FNaNbfZf") == 0)
+		{
+		    if (ident == Id::_sqrt)
+			builtin = BUILTINsqrt;
+		}
 	    }
 	}
     }
@@ -75,28 +87,30 @@
     {
 	case BUILTINsin:
 	    if (arg0->op == TOKfloat64)
-		e = new RealExp(0, sinl(arg0->toReal()), Type::tfloat80);
+		e = new RealExp(0, sinl(arg0->toReal()), arg0->type);
 	    break;
 
 	case BUILTINcos:
 	    if (arg0->op == TOKfloat64)
-		e = new RealExp(0, cosl(arg0->toReal()), Type::tfloat80);
+		e = new RealExp(0, cosl(arg0->toReal()), arg0->type);
 	    break;
 
 	case BUILTINtan:
 	    if (arg0->op == TOKfloat64)
-		e = new RealExp(0, tanl(arg0->toReal()), Type::tfloat80);
+		e = new RealExp(0, tanl(arg0->toReal()), arg0->type);
 	    break;
 
 	case BUILTINsqrt:
 	    if (arg0->op == TOKfloat64)
-		e = new RealExp(0, sqrtl(arg0->toReal()), Type::tfloat80);
+		e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type);
 	    break;
 
 	case BUILTINfabs:
 	    if (arg0->op == TOKfloat64)
-		e = new RealExp(0, fabsl(arg0->toReal()), Type::tfloat80);
+		e = new RealExp(0, fabsl(arg0->toReal()), arg0->type);
 	    break;
     }
     return e;
 }
+
+#endif
--- a/dmd2/cast.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/cast.c	Sat May 30 17:23:32 2009 +0100
@@ -1,1705 +1,1779 @@
-
-// 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>
-
-#if _WIN32 || IN_GCC || IN_LLVM
-#include "mem.h"
-#else
-#include "../root/mem.h"
-#endif
-
-#include "expression.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-
-/* ==================== implicitCast ====================== */
-
-/**************************************
- * Do an implicit cast.
- * Issue error if it can't be done.
- */
-
-Expression *Expression::implicitCastTo(Scope *sc, Type *t)
-{
-    //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
-
-    MATCH match = implicitConvTo(t);
-    if (match)
-    {	TY tyfrom = type->toBasetype()->ty;
-	TY tyto = t->toBasetype()->ty;
-	if (global.params.warnings &&
-	    Type::impcnvWarn[tyfrom][tyto] &&
-	    op != TOKint64)
-	{
-	    Expression *e = optimize(WANTflags | WANTvalue);
-
-	    if (e->op == TOKint64)
-		return e->implicitCastTo(sc, t);
-
-	    if (tyfrom == Tint32 &&
-		(op == TOKadd || op == TOKmin ||
-		 op == TOKand || op == TOKor || op == TOKxor)
-	       )
-	    {
-		/* This is really only a semi-kludge fix,
-		 * we really should look at the operands of op
-		 * and see if they are narrower types.
-		 * For example, b=b|b and b=b|7 and s=b+b should be allowed,
-		 * but b=b|i should be an error.
-		 */
-		;
-	    }
-	    else
-	    {
-		warning("%s: implicit conversion of expression (%s) of type %s to %s can cause loss of data",
-		    loc.toChars(), toChars(), type->toChars(), t->toChars());
-	    }
-	}
-#if DMDV2
-	if (match == MATCHconst && t == type->constOf())
-	{
-	    Expression *e = copy();
-	    e->type = t;
-	    return e;
-	}
-#endif
-	return castTo(sc, t);
-    }
-
-    Expression *e = optimize(WANTflags | WANTvalue);
-    if (e != this)
-	return e->implicitCastTo(sc, t);
-
-#if 0
-printf("ty = %d\n", type->ty);
-print();
-type->print();
-printf("to:\n");
-t->print();
-printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
-//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
-fflush(stdout);
-#endif
-    if (!t->deco)
-    {	/* Can happen with:
-	 *    enum E { One }
-	 *    class A
-	 *    { static void fork(EDG dg) { dg(E.One); }
-	 *	alias void delegate(E) EDG;
-	 *    }
-	 * Should eventually make it work.
-	 */
-	error("forward reference to type %s", t->toChars());
-    }
-    else if (t->reliesOnTident())
-	error("forward reference to type %s", t->reliesOnTident()->toChars());
-
-    error("cannot implicitly convert expression (%s) of type %s to %s",
-	toChars(), type->toChars(), t->toChars());
-    return castTo(sc, t);
-}
-
-/*******************************************
- * Return !=0 if we can implicitly convert this to type t.
- * Don't do the actual cast.
- */
-
-MATCH Expression::implicitConvTo(Type *t)
-{
-#if 0
-    printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    //static int nest; if (++nest == 10) halt();
-    if (!type)
-    {	error("%s is not an expression", toChars());
-	type = Type::terror;
-    }
-    Expression *e = optimize(WANTvalue | WANTflags);
-    if (e->type == t)
-	return MATCHexact;
-    if (e != this)
-    {	//printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
-	return e->implicitConvTo(t);
-    }
-    MATCH match = type->implicitConvTo(t);
-    if (match != MATCHnomatch)
-	return match;
-#if 0
-    Type *tb = t->toBasetype();
-    if (tb->ty == Tdelegate)
-    {	TypeDelegate *td = (TypeDelegate *)tb;
-	TypeFunction *tf = (TypeFunction *)td->nextOf();
-
-	if (!tf->varargs &&
-	    !(tf->arguments && tf->arguments->dim)
-	   )
-	{
-	    match = type->implicitConvTo(tf->nextOf());
-	    if (match)
-		return match;
-	    if (tf->nextOf()->toBasetype()->ty == Tvoid)
-		return MATCHconvert;
-	}
-    }
-#endif
-    return MATCHnomatch;
-}
-
-
-MATCH IntegerExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    MATCH m = type->implicitConvTo(t);
-    if (m >= MATCHconst)
-	return m;
-
-    TY ty = type->toBasetype()->ty;
-    TY toty = t->toBasetype()->ty;
-
-    if (m == MATCHnomatch && t->ty == Tenum)
-	goto Lno;
-
-    switch (ty)
-    {
-	case Tbit:
-	case Tbool:
-	    value &= 1;
-	    ty = Tint32;
-	    break;
-
-	case Tint8:
-	    value = (signed char)value;
-	    ty = Tint32;
-	    break;
-
-	case Tchar:
-	case Tuns8:
-	    value &= 0xFF;
-	    ty = Tint32;
-	    break;
-
-	case Tint16:
-	    value = (short)value;
-	    ty = Tint32;
-	    break;
-
-	case Tuns16:
-	case Twchar:
-	    value &= 0xFFFF;
-	    ty = Tint32;
-	    break;
-
-	case Tint32:
-	    value = (int)value;
-	    break;
-
-	case Tuns32:
-	case Tdchar:
-	    value &= 0xFFFFFFFF;
-	    ty = Tuns32;
-	    break;
-
-	default:
-	    break;
-    }
-
-    // Only allow conversion if no change in value
-    switch (toty)
-    {
-	case Tbit:
-	case Tbool:
-	    if ((value & 1) != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tint8:
-	    if ((signed char)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tchar:
-	case Tuns8:
-	    //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value);
-	    if ((unsigned char)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tint16:
-	    if ((short)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tuns16:
-	    if ((unsigned short)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tint32:
-	    if (ty == Tuns32)
-	    {
-	    }
-	    else if ((int)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tuns32:
-	    if (ty == Tint32)
-	    {
-	    }
-	    else if ((unsigned)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tdchar:
-	    if (value > 0x10FFFFUL)
-		goto Lno;
-	    goto Lyes;
-
-	case Twchar:
-	    if ((unsigned short)value != value)
-		goto Lno;
-	    goto Lyes;
-
-	case Tfloat32:
-	{
-	    volatile float f;
-	    if (type->isunsigned())
-	    {
-		f = (float)value;
-		if (f != value)
-		    goto Lno;
-	    }
-	    else
-	    {
-		f = (float)(long long)value;
-		if (f != (long long)value)
-		    goto Lno;
-	    }
-	    goto Lyes;
-	}
-
-	case Tfloat64:
-	{
-	    volatile double f;
-	    if (type->isunsigned())
-	    {
-		f = (double)value;
-		if (f != value)
-		    goto Lno;
-	    }
-	    else
-	    {
-		f = (double)(long long)value;
-		if (f != (long long)value)
-		    goto Lno;
-	    }
-	    goto Lyes;
-	}
-
-	case Tfloat80:
-	{
-	    volatile long double f;
-	    if (type->isunsigned())
-	    {
-		f = (long double)value;
-		if (f != value)
-		    goto Lno;
-	    }
-	    else
-	    {
-		f = (long double)(long long)value;
-		if (f != (long long)value)
-		    goto Lno;
-	    }
-	    goto Lyes;
-	}
-
-	case Tpointer:
-//printf("type = %s\n", type->toBasetype()->toChars());
-//printf("t = %s\n", t->toBasetype()->toChars());
-	    if (ty == Tpointer &&
-	        type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
-	    {	/* Allow things like:
-		 *	const char* P = cast(char *)3;
-		 *	char* q = P;
-		 */
-		goto Lyes;
-	    }
-	    break;
-    }
-    return Expression::implicitConvTo(t);
-
-Lyes:
-    //printf("MATCHconvert\n");
-    return MATCHconvert;
-
-Lno:
-    //printf("MATCHnomatch\n");
-    return MATCHnomatch;
-}
-
-MATCH NullExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
-	toChars(), type->toChars(), t->toChars(), committed);
-#endif
-    if (this->type->equals(t))
-	return MATCHexact;
-
-    /* Allow implicit conversions from invariant to mutable|const,
-     * and mutable to invariant. It works because, after all, a null
-     * doesn't actually point to anything.
-     */
-    if (t->invariantOf()->equals(type->invariantOf()))
-	return MATCHconst;
-
-    // NULL implicitly converts to any pointer type or dynamic array
-    if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
-    {
-	if (t->ty == Ttypedef)
-	    t = ((TypeTypedef *)t)->sym->basetype;
-	if (t->ty == Tpointer || t->ty == Tarray ||
-	    t->ty == Taarray  || t->ty == Tclass ||
-	    t->ty == Tdelegate)
-	    return committed ? MATCHconvert : MATCHexact;
-    }
-    return Expression::implicitConvTo(t);
-}
-
-#if DMDV2
-MATCH StructLiteralExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    MATCH m = Expression::implicitConvTo(t);
-    if (m != MATCHnomatch)
-	return m;
-    if (type->ty == t->ty && type->ty == Tstruct &&
-	((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
-    {
-	m = MATCHconst;
-	for (int i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    Type *te = e->type;
-	    if (t->mod == 0)
-		te = te->mutableOf();
-	    else
-	    {	assert(t->mod == MODinvariant);
-		te = te->invariantOf();
-	    }
-	    MATCH m2 = e->implicitConvTo(te);
-	    //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
-	    if (m2 < m)
-		m = m2;
-	}
-    }
-    return m;
-}
-#endif
-
-MATCH StringExp::implicitConvTo(Type *t)
-{   MATCH m;
-
-#if 0
-    printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
-	toChars(), committed, type->toChars(), t->toChars());
-#endif
-    if (!committed)
-    {
-    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
-    {
-	return MATCHnomatch;
-    }
-    if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
-    {
-	TY tyn = type->nextOf()->ty;
-	if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
-	{   Type *tn;
-	    MATCH m;
-
-	    switch (t->ty)
-	    {
-		case Tsarray:
-		    if (type->ty == Tsarray)
-		    {
-			if (((TypeSArray *)type)->dim->toInteger() !=
-			    ((TypeSArray *)t)->dim->toInteger())
-			    return MATCHnomatch;
-			TY tynto = t->nextOf()->ty;
-			if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
-			    return MATCHexact;
-		    }
-		case Tarray:
-		case Tpointer:
-		    tn = t->nextOf();
-		    m = MATCHexact;
-		    if (type->nextOf()->mod != tn->mod)
-		    {	if (!tn->isConst())
-			    return MATCHnomatch;
-			m = MATCHconst;
-		    }
-		    switch (tn->ty)
-		    {
-			case Tchar:
-			case Twchar:
-			case Tdchar:
-			    return m;
-		    }
-		    break;
-	    }
-	}
-    }
-    }
-    return Expression::implicitConvTo(t);
-#if 0
-    m = (MATCH)type->implicitConvTo(t);
-    if (m)
-    {
-	return m;
-    }
-
-    return MATCHnomatch;
-#endif
-}
-
-MATCH ArrayLiteralExp::implicitConvTo(Type *t)
-{   MATCH result = MATCHexact;
-
-#if 0
-    printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    Type *typeb = type->toBasetype();
-    Type *tb = t->toBasetype();
-    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
-	(typeb->ty == Tarray || typeb->ty == Tsarray))
-    {
-	if (tb->ty == Tsarray)
-	{   TypeSArray *tsa = (TypeSArray *)tb;
-	    if (elements->dim != tsa->dim->toInteger())
-		result = MATCHnomatch;
-	}
-
-	for (int i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    MATCH m = (MATCH)e->implicitConvTo(tb->nextOf());
-	    if (m < result)
-		result = m;			// remember worst match
-	    if (result == MATCHnomatch)
-		break;				// no need to check for worse
-	}
-	return result;
-    }
-    else
-	return Expression::implicitConvTo(t);
-}
-
-MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
-{   MATCH result = MATCHexact;
-
-    Type *typeb = type->toBasetype();
-    Type *tb = t->toBasetype();
-    if (tb->ty == Taarray && typeb->ty == Taarray)
-    {
-	for (size_t i = 0; i < keys->dim; i++)
-	{   Expression *e = (Expression *)keys->data[i];
-	    MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index);
-	    if (m < result)
-		result = m;			// remember worst match
-	    if (result == MATCHnomatch)
-		break;				// no need to check for worse
-	    e = (Expression *)values->data[i];
-	    m = (MATCH)e->implicitConvTo(tb->nextOf());
-	    if (m < result)
-		result = m;			// remember worst match
-	    if (result == MATCHnomatch)
-		break;				// no need to check for worse
-	}
-	return result;
-    }
-    else
-	return Expression::implicitConvTo(t);
-}
-
-MATCH AddrExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    MATCH result;
-
-    result = type->implicitConvTo(t);
-    //printf("\tresult = %d\n", result);
-
-    if (result == MATCHnomatch)
-    {
-	// Look for pointers to functions where the functions are overloaded.
-
-	t = t->toBasetype();
-
-	if (e1->op == TOKoverloadset &&
-	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
-	{   OverExp *eo = (OverExp *)e1;
-	    FuncDeclaration *f = NULL;
-	    for (int i = 0; i < eo->vars->a.dim; i++)
-	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
-		FuncDeclaration *f2 = s->isFuncDeclaration();
-		assert(f2);
-		if (f2->overloadExactMatch(t->nextOf()))
-		{   if (f)
-			/* Error if match in more than one overload set,
-			 * even if one is a 'better' match than the other.
-			 */
-			ScopeDsymbol::multiplyDefined(loc, f, f2);
-		    else
-			f = f2;
-		    result = MATCHexact;
-		}
-	    }
-	}
-
-	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
-	    t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
-	    e1->op == TOKvar)
-	{
-// LDC: it happens for us
-#if !IN_LLVM
-	    /* I don't think this can ever happen -
-	     * it should have been
-	     * converted to a SymOffExp.
-	     */
-	    assert(0);
-#endif
-	    VarExp *ve = (VarExp *)e1;
-	    FuncDeclaration *f = ve->var->isFuncDeclaration();
-	    if (f && f->overloadExactMatch(t->nextOf()))
-		result = MATCHexact;
-	}
-    }
-    //printf("\tresult = %d\n", result);
-    return result;
-}
-
-MATCH SymOffExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    MATCH result;
-
-    result = type->implicitConvTo(t);
-    //printf("\tresult = %d\n", result);
-
-    if (result == MATCHnomatch)
-    {
-	// Look for pointers to functions where the functions are overloaded.
-	FuncDeclaration *f;
-
-	t = t->toBasetype();
-	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
-	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
-	{
-	    f = var->isFuncDeclaration();
-	    if (f)
-	    {	f = f->overloadExactMatch(t->nextOf());
-		if (f)
-		{   if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
-			(t->ty == Tpointer && !(f->needThis() || f->isNested())))
-		    {
-			result = MATCHexact;
-		    }
-		}
-	    }
-	}
-    }
-    //printf("\tresult = %d\n", result);
-    return result;
-}
-
-MATCH DelegateExp::implicitConvTo(Type *t)
-{
-#if 0
-    printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    MATCH result;
-
-    result = type->implicitConvTo(t);
-
-    if (result == MATCHnomatch)
-    {
-	// Look for pointers to functions where the functions are overloaded.
-	FuncDeclaration *f;
-
-	t = t->toBasetype();
-	if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction &&
-	    t->ty == Tdelegate && t->nextOf()->ty == Tfunction)
-	{
-	    if (func && func->overloadExactMatch(t->nextOf()))
-		result = MATCHexact;
-	}
-    }
-    return result;
-}
-
-MATCH CondExp::implicitConvTo(Type *t)
-{
-    MATCH m1;
-    MATCH m2;
-
-    m1 = e1->implicitConvTo(t);
-    m2 = e2->implicitConvTo(t);
-
-    // Pick the worst match
-    return (m1 < m2) ? m1 : m2;
-}
-
-
-/* ==================== castTo ====================== */
-
-/**************************************
- * Do an explicit cast.
- */
-
-Expression *Expression::castTo(Scope *sc, Type *t)
-{
-    //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
-#if 0
-    printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    if (type == t)
-	return this;
-    Expression *e = this;
-    Type *tb = t->toBasetype();
-    Type *typeb = type->toBasetype();
-    if (tb != typeb)
-    {
-	// Do (type *) cast of (type [dim])
-	if (tb->ty == Tpointer &&
-	    typeb->ty == Tsarray
-	   )
-	{
-	    //printf("Converting [dim] to *\n");
-
-	    if (typeb->size(loc) == 0)
-		e = new NullExp(loc);
-	    else
-		e = new AddrExp(loc, e);
-	}
-#if 0
-	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
-	{
-	    TypeDelegate *td = (TypeDelegate *)tb;
-	    TypeFunction *tf = (TypeFunction *)td->nextOf();
-	    return toDelegate(sc, tf->nextOf());
-	}
-#endif
-	else
-	{
-	    e = new CastExp(loc, e, tb);
-	}
-    }
-    else
-    {
-	e = e->copy();	// because of COW for assignment to e->type
-    }
-    assert(e != this);
-    e->type = t;
-    //printf("Returning: %s\n", e->toChars());
-    return e;
-}
-
-
-Expression *RealExp::castTo(Scope *sc, Type *t)
-{   Expression *e = this;
-    if (type != t)
-    {
-	if ((type->isreal() && t->isreal()) ||
-	    (type->isimaginary() && t->isimaginary())
-	   )
-	{   e = copy();
-	    e->type = t;
-	}
-	else
-	    e = Expression::castTo(sc, t);
-    }
-    return e;
-}
-
-
-Expression *ComplexExp::castTo(Scope *sc, Type *t)
-{   Expression *e = this;
-    if (type != t)
-    {
-	if (type->iscomplex() && t->iscomplex())
-	{   e = copy();
-	    e->type = t;
-	}
-	else
-	    e = Expression::castTo(sc, t);
-    }
-    return e;
-}
-
-
-Expression *NullExp::castTo(Scope *sc, Type *t)
-{   NullExp *e;
-    Type *tb;
-
-    //printf("NullExp::castTo(t = %p)\n", t);
-    if (type == t)
-    {
-	committed = 1;
-	return this;
-    }
-    e = (NullExp *)copy();
-    e->committed = 1;
-    tb = t->toBasetype();
-    e->type = type->toBasetype();
-    if (tb != e->type)
-    {
-	// NULL implicitly converts to any pointer type or dynamic array
-	if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
-	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
-	     tb->ty == Tdelegate))
-	{
-#if 0
-	    if (tb->ty == Tdelegate)
-	    {   TypeDelegate *td = (TypeDelegate *)tb;
-		TypeFunction *tf = (TypeFunction *)td->nextOf();
-
-		if (!tf->varargs &&
-		    !(tf->arguments && tf->arguments->dim)
-		   )
-		{
-		    return Expression::castTo(sc, t);
-		}
-	    }
-#endif
-	}
-	else
-	{
-	    return e->Expression::castTo(sc, t);
-	}
-    }
-    e->type = t;
-    return e;
-}
-
-Expression *StringExp::castTo(Scope *sc, Type *t)
-{
-    /* This follows copy-on-write; any changes to 'this'
-     * will result in a copy.
-     * The this->string member is considered immutable.
-     */
-    StringExp *se;
-    Type *tb;
-    int copied = 0;
-
-    //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
-
-    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
-    {
-	error("cannot convert string literal to void*");
-    }
-
-    se = this;
-    if (!committed)
-    {   se = (StringExp *)copy();
-	se->committed = 1;
-	copied = 1;
-    }
-
-    if (type == t)
-    {
-	return se;
-    }
-
-    tb = t->toBasetype();
-    //printf("\ttype = %s\n", type->toChars());
-    if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
-	return Expression::castTo(sc, t);
-
-    Type *typeb = type->toBasetype();
-    if (typeb == tb)
-    {
-	if (!copied)
-	{   se = (StringExp *)copy();
-	    copied = 1;
-	}
-	se->type = t;
-	return se;
-    }
-
-    if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
-    {	if (!copied)
-	{   se = (StringExp *)copy();
-	    copied = 1;
-	}
-	goto Lcast;
-    }
-    if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
-    {	if (!copied)
-	{   se = (StringExp *)copy();
-	    copied = 1;
-	}
-	goto Lcast;
-    }
-
-    if (typeb->nextOf()->size() == tb->nextOf()->size())
-    {
-	if (!copied)
-	{   se = (StringExp *)copy();
-	    copied = 1;
-	}
-	if (tb->ty == Tsarray)
-	    goto L2;	// handle possible change in static array dimension
-	se->type = t;
-	return se;
-    }
-
-    if (committed)
-	goto Lcast;
-
-#define X(tf,tt)	((tf) * 256 + (tt))
-    {
-    OutBuffer buffer;
-    size_t newlen = 0;
-    int tfty = typeb->nextOf()->toBasetype()->ty;
-    int ttty = tb->nextOf()->toBasetype()->ty;
-    switch (X(tfty, ttty))
-    {
-	case X(Tchar, Tchar):
-	case X(Twchar,Twchar):
-	case X(Tdchar,Tdchar):
-	    break;
-
-	case X(Tchar, Twchar):
-	    for (size_t u = 0; u < len;)
-	    {	unsigned c;
-		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
-		if (p)
-		    error("%s", p);
-		else
-		    buffer.writeUTF16(c);
-	    }
-	    newlen = buffer.offset / 2;
-	    buffer.writeUTF16(0);
-	    goto L1;
-
-	case X(Tchar, Tdchar):
-	    for (size_t u = 0; u < len;)
-	    {	unsigned c;
-		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
-		if (p)
-		    error("%s", p);
-		buffer.write4(c);
-		newlen++;
-	    }
-	    buffer.write4(0);
-	    goto L1;
-
-	case X(Twchar,Tchar):
-	    for (size_t u = 0; u < len;)
-	    {	unsigned c;
-		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
-		if (p)
-		    error("%s", p);
-		else
-		    buffer.writeUTF8(c);
-	    }
-	    newlen = buffer.offset;
-	    buffer.writeUTF8(0);
-	    goto L1;
-
-	case X(Twchar,Tdchar):
-	    for (size_t u = 0; u < len;)
-	    {	unsigned c;
-		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
-		if (p)
-		    error("%s", p);
-		buffer.write4(c);
-		newlen++;
-	    }
-	    buffer.write4(0);
-	    goto L1;
-
-	case X(Tdchar,Tchar):
-	    for (size_t u = 0; u < len; u++)
-	    {
-		unsigned c = ((unsigned *)se->string)[u];
-		if (!utf_isValidDchar(c))
-		    error("invalid UCS-32 char \\U%08x", c);
-		else
-		    buffer.writeUTF8(c);
-		newlen++;
-	    }
-	    newlen = buffer.offset;
-	    buffer.writeUTF8(0);
-	    goto L1;
-
-	case X(Tdchar,Twchar):
-	    for (size_t u = 0; u < len; u++)
-	    {
-		unsigned c = ((unsigned *)se->string)[u];
-		if (!utf_isValidDchar(c))
-		    error("invalid UCS-32 char \\U%08x", c);
-		else
-		    buffer.writeUTF16(c);
-		newlen++;
-	    }
-	    newlen = buffer.offset / 2;
-	    buffer.writeUTF16(0);
-	    goto L1;
-
-	L1:
-	    if (!copied)
-	    {   se = (StringExp *)copy();
-		copied = 1;
-	    }
-	    se->string = buffer.extractData();
-	    se->len = newlen;
-	    se->sz = tb->nextOf()->size();
-	    break;
-
-	default:
-	    assert(typeb->nextOf()->size() != tb->nextOf()->size());
-	    goto Lcast;
-    }
-    }
-#undef X
-L2:
-    assert(copied);
-
-    // See if need to truncate or extend the literal
-    if (tb->ty == Tsarray)
-    {
-	int dim2 = ((TypeSArray *)tb)->dim->toInteger();
-
-	//printf("dim from = %d, to = %d\n", se->len, dim2);
-
-	// Changing dimensions
-	if (dim2 != se->len)
-	{
-	    // Copy when changing the string literal
-	    unsigned newsz = se->sz;
-	    void *s;
-	    int d;
-
-	    d = (dim2 < se->len) ? dim2 : se->len;
-	    s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
-	    memcpy(s, se->string, d * newsz);
-	    // Extend with 0, add terminating 0
-	    memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
-	    se->string = s;
-	    se->len = dim2;
-	}
-    }
-    se->type = t;
-    return se;
-
-Lcast:
-    Expression *e = new CastExp(loc, se, t);
-    e->type = t;	// so semantic() won't be run on e
-    return e;
-}
-
-Expression *AddrExp::castTo(Scope *sc, Type *t)
-{
-    Type *tb;
-
-#if 0
-    printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    Expression *e = this;
-
-    tb = t->toBasetype();
-    type = type->toBasetype();
-    if (tb != type)
-    {
-	// Look for pointers to functions where the functions are overloaded.
-
-	if (e1->op == TOKoverloadset &&
-	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
-	{   OverExp *eo = (OverExp *)e1;
-	    FuncDeclaration *f = NULL;
-	    for (int i = 0; i < eo->vars->a.dim; i++)
-	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
-		FuncDeclaration *f2 = s->isFuncDeclaration();
-		assert(f2);
-		if (f2->overloadExactMatch(t->nextOf()))
-		{   if (f)
-			/* Error if match in more than one overload set,
-			 * even if one is a 'better' match than the other.
-			 */
-			ScopeDsymbol::multiplyDefined(loc, f, f2);
-		    else
-			f = f2;
-		}
-	    }
-	    if (f)
-	    {	f->tookAddressOf++;
-		SymOffExp *se = new SymOffExp(loc, f, 0, 0);
-		se->semantic(sc);
-		// Let SymOffExp::castTo() do the heavy lifting
-		return se->castTo(sc, t);
-	    }
-	}
-
-
-	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
-	    tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
-	    e1->op == TOKvar)
-	{
-	    VarExp *ve = (VarExp *)e1;
-	    FuncDeclaration *f = ve->var->isFuncDeclaration();
-	    if (f)
-	    {
-// LDC: not in ldc
-#if !IN_LLVM
-		assert(0);	// should be SymOffExp instead
-#endif
-		f = f->overloadExactMatch(tb->nextOf());
-		if (f)
-		{
-		    e = new VarExp(loc, f);
-		    e->type = f->type;
-		    e = new AddrExp(loc, e);
-		    e->type = t;
-		    return e;
-		}
-	    }
-	}
-	e = Expression::castTo(sc, t);
-    }
-    e->type = t;
-    return e;
-}
-
-
-Expression *TupleExp::castTo(Scope *sc, Type *t)
-{   TupleExp *e = (TupleExp *)copy();
-    e->exps = (Expressions *)exps->copy();
-    for (size_t i = 0; i < e->exps->dim; i++)
-    {   Expression *ex = (Expression *)e->exps->data[i];
-	ex = ex->castTo(sc, t);
-	e->exps->data[i] = (void *)ex;
-    }
-    return e;
-}
-
-
-Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
-{
-#if 0
-    printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    if (type == t)
-	return this;
-    ArrayLiteralExp *e = this;
-    Type *typeb = type->toBasetype();
-    Type *tb = t->toBasetype();
-    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
-	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
-	// Not trying to convert non-void[] to void[]
-	!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
-    {
-	if (tb->ty == Tsarray)
-	{   TypeSArray *tsa = (TypeSArray *)tb;
-	    if (elements->dim != tsa->dim->toInteger())
-		goto L1;
-	}
-
-	e = (ArrayLiteralExp *)copy();
-	e->elements = (Expressions *)elements->copy();
-	for (int i = 0; i < elements->dim; i++)
-	{   Expression *ex = (Expression *)elements->data[i];
-	    ex = ex->castTo(sc, tb->nextOf());
-	    e->elements->data[i] = (void *)ex;
-	}
-	e->type = t;
-	return e;
-    }
-    if (tb->ty == Tpointer && typeb->ty == Tsarray)
-    {
-	e = (ArrayLiteralExp *)copy();
-	e->type = typeb->nextOf()->pointerTo();
-    }
-L1:
-    return e->Expression::castTo(sc, t);
-}
-
-Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
-{
-    if (type == t)
-	return this;
-    AssocArrayLiteralExp *e = this;
-    Type *typeb = type->toBasetype();
-    Type *tb = t->toBasetype();
-    if (tb->ty == Taarray && typeb->ty == Taarray &&
-	tb->nextOf()->toBasetype()->ty != Tvoid)
-    {
-	e = (AssocArrayLiteralExp *)copy();
-	e->keys = (Expressions *)keys->copy();
-	e->values = (Expressions *)values->copy();
-	assert(keys->dim == values->dim);
-	for (size_t i = 0; i < keys->dim; i++)
-	{   Expression *ex = (Expression *)values->data[i];
-	    ex = ex->castTo(sc, tb->nextOf());
-	    e->values->data[i] = (void *)ex;
-
-	    ex = (Expression *)keys->data[i];
-	    ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
-	    e->keys->data[i] = (void *)ex;
-	}
-	e->type = t;
-	return e;
-    }
-L1:
-    return e->Expression::castTo(sc, t);
-}
-
-Expression *SymOffExp::castTo(Scope *sc, Type *t)
-{
-#if 0
-    printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    if (type == t && hasOverloads == 0)
-	return this;
-    Expression *e;
-    Type *tb = t->toBasetype();
-    Type *typeb = type->toBasetype();
-    if (tb != typeb)
-    {
-	// Look for pointers to functions where the functions are overloaded.
-	FuncDeclaration *f;
-
-	if (hasOverloads &&
-	    typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
-	    (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
-	{
-	    f = var->isFuncDeclaration();
-	    if (f)
-	    {
-		f = f->overloadExactMatch(tb->nextOf());
-		if (f)
-		{
-		    if (tb->ty == Tdelegate && f->needThis() && hasThis(sc))
-		    {
-			e = new DelegateExp(loc, new ThisExp(loc), f);
-			e = e->semantic(sc);
-		    }
-		    else if (tb->ty == Tdelegate && f->isNested())
-		    {
-			e = new DelegateExp(loc, new IntegerExp(0), f);
-			e = e->semantic(sc);
-		    }
-		    else
-		    {
-			e = new SymOffExp(loc, f, 0);
-			e->type = t;
-		    }
-		    f->tookAddressOf++;
-		    return e;
-		}
-	    }
-	}
-	e = Expression::castTo(sc, t);
-    }
-    else
-    {	e = copy();
-	e->type = t;
-	((SymOffExp *)e)->hasOverloads = 0;
-    }
-    return e;
-}
-
-Expression *DelegateExp::castTo(Scope *sc, Type *t)
-{
-#if 0
-    printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
-	toChars(), type->toChars(), t->toChars());
-#endif
-    static char msg[] = "cannot form delegate due to covariant return type";
-
-    Expression *e = this;
-    Type *tb = t->toBasetype();
-    Type *typeb = type->toBasetype();
-    if (tb != typeb)
-    {
-	// Look for delegates to functions where the functions are overloaded.
-	FuncDeclaration *f;
-
-	if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction &&
-	    tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction)
-	{
-	    if (func)
-	    {
-		f = func->overloadExactMatch(tb->nextOf());
-		if (f)
-		{   int offset;
-		    if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
-			error("%s", msg);
-		    f->tookAddressOf++;
-		    e = new DelegateExp(loc, e1, f);
-		    e->type = t;
-		    return e;
-		}
-		if (func->tintro)
-		    error("%s", msg);
-	    }
-	}
-	e = Expression::castTo(sc, t);
-    }
-    else
-    {	int offset;
-
-	func->tookAddressOf++;
-	if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset)
-	    error("%s", msg);
-	e = copy();
-	e->type = t;
-    }
-    return e;
-}
-
-Expression *CondExp::castTo(Scope *sc, Type *t)
-{
-    Expression *e = this;
-
-    if (type != t)
-    {
-	if (1 || e1->op == TOKstring || e2->op == TOKstring)
-	{   e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
-	    e->type = t;
-	}
-	else
-	    e = Expression::castTo(sc, t);
-    }
-    return e;
-}
-
-/* ==================== ====================== */
-
-/****************************************
- * Scale addition/subtraction to/from pointer.
- */
-
-Expression *BinExp::scaleFactor(Scope *sc)
-{   d_uns64 stride;
-    Type *t1b = e1->type->toBasetype();
-    Type *t2b = e2->type->toBasetype();
-
-    if (t1b->ty == Tpointer && t2b->isintegral())
-    {   // Need to adjust operator by the stride
-	// Replace (ptr + int) with (ptr + (int * stride))
-	Type *t = Type::tptrdiff_t;
-
-	stride = t1b->nextOf()->size(loc);
-	if (!t->equals(t2b))
-	    e2 = e2->castTo(sc, t);
-    // LDC: llvm uses typesafe pointer arithmetic
-    #if !IN_LLVM
-	e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
-    #endif
-	e2->type = t;
-	type = e1->type;
-    }
-    else if (t2b->ty == Tpointer && t1b->isintegral())
-    {   // Need to adjust operator by the stride
-	// Replace (int + ptr) with (ptr + (int * stride))
-	Type *t = Type::tptrdiff_t;
-	Expression *e;
-
-	stride = t2b->nextOf()->size(loc);
-	if (!t->equals(t1b))
-	    e = e1->castTo(sc, t);
-	else
-	    e = e1;
-    #if !IN_LLVM
-	e = new MulExp(loc, e, new IntegerExp(0, stride, t));
-    #endif
-	e->type = t;
-	type = e2->type;
-	e1 = e2;
-	e2 = e;
-    }
-    return this;
-}
-
-/**************************************
- * Combine types.
- * Output:
- *	*pt	merged type, if *pt is not NULL
- *	*pe1	rewritten e1
- *	*pe2	rewritten e2
- * Returns:
- *	!=0	success
- *	0	failed
- */
-
-int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
-{
-    //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
-    //dump(0);
-
-    Expression *e1 = (*pe1)->integralPromotions(sc);
-    Expression *e2 = (*pe2)->integralPromotions(sc);
-
-    Type *t1 = e1->type;
-    Type *t2 = e2->type;
-    assert(t1);
-    Type *t = t1;
-
-    //if (t1) printf("\tt1 = %s\n", t1->toChars());
-    //if (t2) printf("\tt2 = %s\n", t2->toChars());
-#ifdef DEBUG
-    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
-#endif
-    assert(t2);
-
-    Type *t1b = t1->toBasetype();
-    Type *t2b = t2->toBasetype();
-
-    TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
-    if (ty != Terror)
-    {	TY ty1;
-	TY ty2;
-
-	ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
-	ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
-
-	if (t1b->ty == ty1)	// if no promotions
-	{
-	    if (t1 == t2)
-	    {
-		t = t1;
-		goto Lret;
-	    }
-
-	    if (t1b == t2b)
-	    {
-		t = t1b;
-		goto Lret;
-	    }
-	}
-
-	t = Type::basic[ty];
-
-	t1 = Type::basic[ty1];
-	t2 = Type::basic[ty2];
-	e1 = e1->castTo(sc, t1);
-	e2 = e2->castTo(sc, t2);
-	//printf("after typeCombine():\n");
-	//dump(0);
-	//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
-	goto Lret;
-    }
-
-    t1 = t1b;
-    t2 = t2b;
-
-Lagain:
-    if (t1 == t2)
-    {
-    }
-    else if (t1->ty == Tpointer && t2->ty == Tpointer)
-    {
-	// Bring pointers to compatible type
-	Type *t1n = t1->nextOf();
-	Type *t2n = t2->nextOf();
-
-	if (t1n == t2n)
-	    ;
-	else if (t1n->ty == Tvoid)	// pointers to void are always compatible
-	    t = t2;
-	else if (t2n->ty == Tvoid)
-	    ;
-	else if (t1n->mod != t2n->mod)
-	{
-	    t1 = t1n->mutableOf()->constOf()->pointerTo();
-	    t2 = t2n->mutableOf()->constOf()->pointerTo();
-	    t = t1;
-	    goto Lagain;
-	}
-	else if (t1n->ty == Tclass && t2n->ty == Tclass)
-	{   ClassDeclaration *cd1 = t1n->isClassHandle();
-	    ClassDeclaration *cd2 = t2n->isClassHandle();
-	    int offset;
-
-	    if (cd1->isBaseOf(cd2, &offset))
-	    {
-		if (offset)
-		    e2 = e2->castTo(sc, t);
-	    }
-	    else if (cd2->isBaseOf(cd1, &offset))
-	    {
-		t = t2;
-		if (offset)
-		    e1 = e1->castTo(sc, t);
-	    }
-	    else
-		goto Lincompatible;
-	}
-	else
-	    goto Lincompatible;
-    }
-    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
-	     e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid)
-    {	/*  (T[n] op void*)
-	 *  (T[] op void*)
-	 */
-	goto Lx1;
-    }
-    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
-	     e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid)
-    {	/*  (void* op T[n])
-	 *  (void* op T[])
-	 */
-	goto Lx2;
-    }
-    else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
-    {
-	goto Lt2;
-    }
-    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
-    {
-	goto Lt1;
-    }
-    /* If one is mutable and the other invariant, then retry
-     * with both of them as const
-     */
-    else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
-	     (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
-	     t1->nextOf()->mod != t2->nextOf()->mod
-	    )
-    {
-	if (t1->ty == Tpointer)
-	    t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo();
-	else
-	    t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf();
-
-	if (t2->ty == Tpointer)
-	    t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo();
-	else
-	    t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf();
-	t = t1;
-	goto Lagain;
-    }
-    else if (t1->ty == Tclass || t2->ty == Tclass)
-    {
-	while (1)
-	{
-	    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;
-	    }
-	    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 = tc2->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 (t1->ty == Tstruct && t2->ty == Tstruct)
-    {
-	if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym)
-	    goto Lincompatible;
-    }
-    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
-    {
-	goto Lt2;
-    }
-    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
-    {
-	goto Lt1;
-    }
-    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
-	     e2->implicitConvTo(t1->nextOf()->arrayOf()))
-    {
-     Lx1:
-	t = t1->nextOf()->arrayOf();
-	e1 = e1->castTo(sc, t);
-	e2 = e2->castTo(sc, t);
-    }
-    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
-	     e1->implicitConvTo(t2->nextOf()->arrayOf()))
-    {
-     Lx2:
-	t = t2->nextOf()->arrayOf();
-	e1 = e1->castTo(sc, t);
-	e2 = e2->castTo(sc, t);
-    }
-    else if (t1->isintegral() && t2->isintegral())
-    {
-	assert(0);
-    }
-    else if (e1->op == TOKslice && t1->ty == Tarray &&
-	     e2->implicitConvTo(t1->nextOf()))
-    {	// T[] op T
-	e2 = e2->castTo(sc, t1->nextOf());
-	t = t1->nextOf()->arrayOf();
-    }
-    else if (e2->op == TOKslice && t2->ty == Tarray &&
-	     e1->implicitConvTo(t2->nextOf()))
-    {	// T op T[]
-	e1 = e1->castTo(sc, t2->nextOf());
-	t = t2->nextOf()->arrayOf();
-
-	//printf("test %s\n", e->toChars());
-	e1 = e1->optimize(WANTvalue);
-	if (e && e->isCommutative() && e1->isConst())
-	{   /* Swap operands to minimize number of functions generated
-	     */
-	    //printf("swap %s\n", e->toChars());
-	    Expression *tmp = e1;
-	    e1 = e2;
-	    e2 = tmp;
-	}
-    }
-    else
-    {
-     Lincompatible:
-	return 0;
-    }
-Lret:
-    if (!*pt)
-	*pt = t;
-    *pe1 = e1;
-    *pe2 = e2;
-#if 0
-    printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
-    if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
-    if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
-    printf("\ttype = %s\n", t->toChars());
-#endif
-    //dump(0);
-    return 1;
-
-
-Lt1:
-    e2 = e2->castTo(sc, t1);
-    t = t1;
-    goto Lret;
-
-Lt2:
-    e1 = e1->castTo(sc, t2);
-    t = t2;
-    goto Lret;
-}
-
-/************************************
- * Bring leaves to common type.
- */
-
-Expression *BinExp::typeCombine(Scope *sc)
-{
-    Type *t1 = e1->type->toBasetype();
-    Type *t2 = e2->type->toBasetype();
-
-    if (op == TOKmin || op == TOKadd)
-    {
-	if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass))
-	    goto Lerror;
-    }
-
-    if (!typeMerge(sc, this, &type, &e1, &e2))
-	goto Lerror;
-    return this;
-
-Lerror:
-    incompatibleTypes();
-    type = Type::terror;
-    return this;
-}
-
-/***********************************
- * Do integral promotions (convertchk).
- * Don't convert <array of> to <pointer to>
- */
-
-Expression *Expression::integralPromotions(Scope *sc)
-{
-    Expression *e = this;
-
-    //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
-    switch (type->toBasetype()->ty)
-    {
-	case Tvoid:
-	    error("void has no value");
-	    break;
-
-	case Tint8:
-	case Tuns8:
-	case Tint16:
-	case Tuns16:
-	case Tbit:
-	case Tbool:
-	case Tchar:
-	case Twchar:
-	    e = e->castTo(sc, Type::tint32);
-	    break;
-
-	case Tdchar:
-	    e = e->castTo(sc, Type::tuns32);
-	    break;
-    }
-    return e;
-}
-
+
+// Copyright (c) 1999-2009 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 "rmem.h"
+
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+Expression *Expression::implicitCastTo(Scope *sc, Type *t)
+{
+    //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
+
+    MATCH match = implicitConvTo(t);
+    if (match)
+    {	TY tyfrom = type->toBasetype()->ty;
+	TY tyto = t->toBasetype()->ty;
+	if (global.params.warnings &&
+	    Type::impcnvWarn[tyfrom][tyto] &&
+	    op != TOKint64)
+	{
+	    Expression *e = optimize(WANTflags | WANTvalue);
+
+	    if (e->op == TOKint64)
+		return e->implicitCastTo(sc, t);
+
+	    if (tyfrom == Tint32 &&
+		(op == TOKadd || op == TOKmin ||
+		 op == TOKand || op == TOKor || op == TOKxor)
+	       )
+	    {
+		/* This is really only a semi-kludge fix,
+		 * we really should look at the operands of op
+		 * and see if they are narrower types.
+		 * For example, b=b|b and b=b|7 and s=b+b should be allowed,
+		 * but b=b|i should be an error.
+		 */
+		;
+	    }
+	    else
+	    {
+		warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data",
+		    toChars(), type->toChars(), t->toChars());
+	    }
+	}
+#if DMDV2
+	if (match == MATCHconst && t == type->constOf())
+	{
+	    Expression *e = copy();
+	    e->type = t;
+	    return e;
+	}
+#endif
+	return castTo(sc, t);
+    }
+
+    Expression *e = optimize(WANTflags | WANTvalue);
+    if (e != this)
+	return e->implicitCastTo(sc, t);
+
+#if 0
+printf("ty = %d\n", type->ty);
+print();
+type->print();
+printf("to:\n");
+t->print();
+printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
+//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
+fflush(stdout);
+#endif
+    if (!t->deco)
+    {	/* Can happen with:
+	 *    enum E { One }
+	 *    class A
+	 *    { static void fork(EDG dg) { dg(E.One); }
+	 *	alias void delegate(E) EDG;
+	 *    }
+	 * Should eventually make it work.
+	 */
+	error("forward reference to type %s", t->toChars());
+    }
+    else if (t->reliesOnTident())
+	error("forward reference to type %s", t->reliesOnTident()->toChars());
+
+    error("cannot implicitly convert expression (%s) of type %s to %s",
+	toChars(), type->toChars(), t->toChars());
+    return castTo(sc, t);
+}
+
+Expression *StringExp::implicitCastTo(Scope *sc, Type *t)
+{
+    //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
+    unsigned char committed = this->committed;
+    Expression *e = Expression::implicitCastTo(sc, t);
+    if (e->op == TOKstring)
+    {
+	// Retain polysemous nature if it started out that way
+	((StringExp *)e)->committed = committed;
+    }
+    return e;
+}
+
+/*******************************************
+ * Return !=0 if we can implicitly convert this to type t.
+ * Don't do the actual cast.
+ */
+
+MATCH Expression::implicitConvTo(Type *t)
+{
+#if 0
+    printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    //static int nest; if (++nest == 10) halt();
+    if (!type)
+    {	error("%s is not an expression", toChars());
+	type = Type::terror;
+    }
+    Expression *e = optimize(WANTvalue | WANTflags);
+    if (e->type == t)
+	return MATCHexact;
+    if (e != this)
+    {	//printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
+	return e->implicitConvTo(t);
+    }
+    MATCH match = type->implicitConvTo(t);
+    if (match != MATCHnomatch)
+	return match;
+#if 0
+    Type *tb = t->toBasetype();
+    if (tb->ty == Tdelegate)
+    {	TypeDelegate *td = (TypeDelegate *)tb;
+	TypeFunction *tf = (TypeFunction *)td->nextOf();
+
+	if (!tf->varargs &&
+	    !(tf->arguments && tf->arguments->dim)
+	   )
+	{
+	    match = type->implicitConvTo(tf->nextOf());
+	    if (match)
+		return match;
+	    if (tf->nextOf()->toBasetype()->ty == Tvoid)
+		return MATCHconvert;
+	}
+    }
+#endif
+    return MATCHnomatch;
+}
+
+
+MATCH IntegerExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH m = type->implicitConvTo(t);
+    if (m >= MATCHconst)
+	return m;
+
+    TY ty = type->toBasetype()->ty;
+    TY toty = t->toBasetype()->ty;
+
+    if (m == MATCHnomatch && t->ty == Tenum)
+	goto Lno;
+
+    switch (ty)
+    {
+	case Tbit:
+	case Tbool:
+	    value &= 1;
+	    ty = Tint32;
+	    break;
+
+	case Tint8:
+	    value = (signed char)value;
+	    ty = Tint32;
+	    break;
+
+	case Tchar:
+	case Tuns8:
+	    value &= 0xFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint16:
+	    value = (short)value;
+	    ty = Tint32;
+	    break;
+
+	case Tuns16:
+	case Twchar:
+	    value &= 0xFFFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint32:
+	    value = (int)value;
+	    break;
+
+	case Tuns32:
+	case Tdchar:
+	    value &= 0xFFFFFFFF;
+	    ty = Tuns32;
+	    break;
+
+	default:
+	    break;
+    }
+
+    // Only allow conversion if no change in value
+    switch (toty)
+    {
+	case Tbit:
+	case Tbool:
+	    if ((value & 1) != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint8:
+	    if ((signed char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tchar:
+	case Tuns8:
+	    //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+	    if ((unsigned char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint16:
+	    if ((short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns16:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint32:
+	    if (ty == Tuns32)
+	    {
+	    }
+	    else if ((int)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns32:
+	    if (ty == Tint32)
+	    {
+	    }
+	    else if ((unsigned)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tdchar:
+	    if (value > 0x10FFFFUL)
+		goto Lno;
+	    goto Lyes;
+
+	case Twchar:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tfloat32:
+	{
+	    volatile float f;
+	    if (type->isunsigned())
+	    {
+		f = (float)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (float)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat64:
+	{
+	    volatile double f;
+	    if (type->isunsigned())
+	    {
+		f = (double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat80:
+	{
+	    volatile long double f;
+	    if (type->isunsigned())
+	    {
+		f = (long double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (long double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tpointer:
+//printf("type = %s\n", type->toBasetype()->toChars());
+//printf("t = %s\n", t->toBasetype()->toChars());
+	    if (ty == Tpointer &&
+	        type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
+	    {	/* Allow things like:
+		 *	const char* P = cast(char *)3;
+		 *	char* q = P;
+		 */
+		goto Lyes;
+	    }
+	    break;
+    }
+    return Expression::implicitConvTo(t);
+
+Lyes:
+    //printf("MATCHconvert\n");
+    return MATCHconvert;
+
+Lno:
+    //printf("MATCHnomatch\n");
+    return MATCHnomatch;
+}
+
+MATCH NullExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
+	toChars(), type->toChars(), t->toChars(), committed);
+#endif
+    if (this->type->equals(t))
+	return MATCHexact;
+
+    /* Allow implicit conversions from invariant to mutable|const,
+     * and mutable to invariant. It works because, after all, a null
+     * doesn't actually point to anything.
+     */
+    if (t->invariantOf()->equals(type->invariantOf()))
+	return MATCHconst;
+
+    // NULL implicitly converts to any pointer type or dynamic array
+    if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
+    {
+	if (t->ty == Ttypedef)
+	    t = ((TypeTypedef *)t)->sym->basetype;
+	if (t->ty == Tpointer || t->ty == Tarray ||
+	    t->ty == Taarray  || t->ty == Tclass ||
+	    t->ty == Tdelegate)
+	    return committed ? MATCHconvert : MATCHexact;
+    }
+    return Expression::implicitConvTo(t);
+}
+
+#if DMDV2
+MATCH StructLiteralExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH m = Expression::implicitConvTo(t);
+    if (m != MATCHnomatch)
+	return m;
+    if (type->ty == t->ty && type->ty == Tstruct &&
+	((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
+    {
+	m = MATCHconst;
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    Type *te = e->type;
+	    if (t->mod == 0)
+		te = te->mutableOf();
+	    else
+	    {	assert(t->mod == MODinvariant);
+		te = te->invariantOf();
+	    }
+	    MATCH m2 = e->implicitConvTo(te);
+	    //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
+	    if (m2 < m)
+		m = m2;
+	}
+    }
+    return m;
+}
+#endif
+
+MATCH StringExp::implicitConvTo(Type *t)
+{   MATCH m;
+
+#if 0
+    printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
+	toChars(), committed, type->toChars(), t->toChars());
+#endif
+    if (!committed)
+    {
+    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+    {
+	return MATCHnomatch;
+    }
+    if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
+    {
+	TY tyn = type->nextOf()->ty;
+	if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
+	{   Type *tn;
+	    MATCH m;
+
+	    switch (t->ty)
+	    {
+		case Tsarray:
+		    if (type->ty == Tsarray)
+		    {
+			if (((TypeSArray *)type)->dim->toInteger() !=
+			    ((TypeSArray *)t)->dim->toInteger())
+			    return MATCHnomatch;
+			TY tynto = t->nextOf()->ty;
+			if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+			    return MATCHexact;
+		    }
+		    else if (type->ty == Tarray)
+		    {
+			if (length() >
+			    ((TypeSArray *)t)->dim->toInteger())
+			    return MATCHnomatch;
+			TY tynto = t->nextOf()->ty;
+			if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+			    return MATCHexact;
+		    }
+		case Tarray:
+		case Tpointer:
+		    tn = t->nextOf();
+		    m = MATCHexact;
+		    if (type->nextOf()->mod != tn->mod)
+		    {	if (!tn->isConst())
+			    return MATCHnomatch;
+			m = MATCHconst;
+		    }
+		    switch (tn->ty)
+		    {
+			case Tchar:
+			case Twchar:
+			case Tdchar:
+			    return m;
+		    }
+		    break;
+	    }
+	}
+    }
+    }
+    return Expression::implicitConvTo(t);
+#if 0
+    m = (MATCH)type->implicitConvTo(t);
+    if (m)
+    {
+	return m;
+    }
+
+    return MATCHnomatch;
+#endif
+}
+
+MATCH ArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+#if 0
+    printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		result = MATCHnomatch;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(tb->nextOf());
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray)
+    {
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)keys->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	    e = (Expression *)values->data[i];
+	    m = (MATCH)e->implicitConvTo(tb->nextOf());
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AddrExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+
+	t = t->toBasetype();
+
+	if (e1->op == TOKoverloadset &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{   OverExp *eo = (OverExp *)e1;
+	    FuncDeclaration *f = NULL;
+	    for (int i = 0; i < eo->vars->a.dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
+		FuncDeclaration *f2 = s->isFuncDeclaration();
+		assert(f2);
+		if (f2->overloadExactMatch(t->nextOf(), m))
+		{   if (f)
+			/* Error if match in more than one overload set,
+			 * even if one is a 'better' match than the other.
+			 */
+			ScopeDsymbol::multiplyDefined(loc, f, f2);
+		    else
+			f = f2;
+		    result = MATCHexact;
+		}
+	    }
+	}
+
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    /* I don't think this can ever happen -
+	     * it should have been
+	     * converted to a SymOffExp.
+	     */
+	    assert(0);
+	    VarExp *ve = (VarExp *)e1;
+	    FuncDeclaration *f = ve->var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->nextOf(), m))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH SymOffExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {	f = f->overloadExactMatch(t->nextOf(), m);
+		if (f)
+		{   if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
+			(t->ty == Tpointer && !(f->needThis() || f->isNested())))
+		    {
+			result = MATCHexact;
+		    }
+		}
+	    }
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH DelegateExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction &&
+	    t->ty == Tdelegate && t->nextOf()->ty == Tfunction)
+	{
+	    if (func && func->overloadExactMatch(t->nextOf(), m))
+		result = MATCHexact;
+	}
+    }
+    return result;
+}
+
+MATCH CondExp::implicitConvTo(Type *t)
+{
+    MATCH m1;
+    MATCH m2;
+
+    m1 = e1->implicitConvTo(t);
+    m2 = e2->implicitConvTo(t);
+
+    // Pick the worst match
+    return (m1 < m2) ? m1 : m2;
+}
+
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ */
+
+Expression *Expression::castTo(Scope *sc, Type *t)
+{
+    //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
+#if 0
+    printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t)
+	return this;
+    Expression *e = this;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Do (type *) cast of (type [dim])
+	if (tb->ty == Tpointer &&
+	    typeb->ty == Tsarray
+	   )
+	{
+	    //printf("Converting [dim] to *\n");
+
+	    if (typeb->size(loc) == 0)
+		e = new NullExp(loc);
+	    else
+		e = new AddrExp(loc, e);
+	}
+#if 0
+	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
+	{
+	    TypeDelegate *td = (TypeDelegate *)tb;
+	    TypeFunction *tf = (TypeFunction *)td->nextOf();
+	    return toDelegate(sc, tf->nextOf());
+	}
+#endif
+	else
+	{
+	    if (typeb->ty == Tstruct)
+	    {   TypeStruct *ts = (TypeStruct *)typeb;
+		if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) &&
+		    ts->sym->aliasthis)
+		{   /* Forward the cast to our alias this member, rewrite to:
+		     *   cast(to)e1.aliasthis
+		     */
+		    Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident);
+		    Expression *e = new CastExp(loc, e1, tb);
+		    e = e->semantic(sc);
+		    return e;
+		}
+	    }
+	    else if (typeb->ty == Tclass)
+	    {   TypeClass *ts = (TypeClass *)typeb;
+		if (tb->ty != Tclass &&
+		    ts->sym->aliasthis)
+		{   /* Forward the cast to our alias this member, rewrite to:
+		     *   cast(to)e1.aliasthis
+		     */
+		    Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident);
+		    Expression *e = new CastExp(loc, e1, tb);
+		    e = e->semantic(sc);
+		    return e;
+		}
+	    }
+	    e = new CastExp(loc, e, tb);
+	}
+    }
+    else
+    {
+	e = e->copy();	// because of COW for assignment to e->type
+    }
+    assert(e != this);
+    e->type = t;
+    //printf("Returning: %s\n", e->toChars());
+    return e;
+}
+
+
+Expression *RealExp::castTo(Scope *sc, Type *t)
+{   Expression *e = this;
+    if (type != t)
+    {
+	if ((type->isreal() && t->isreal()) ||
+	    (type->isimaginary() && t->isimaginary())
+	   )
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+
+Expression *ComplexExp::castTo(Scope *sc, Type *t)
+{   Expression *e = this;
+    if (type != t)
+    {
+	if (type->iscomplex() && t->iscomplex())
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+
+Expression *NullExp::castTo(Scope *sc, Type *t)
+{   NullExp *e;
+    Type *tb;
+
+    //printf("NullExp::castTo(t = %p)\n", t);
+    if (type == t)
+    {
+	committed = 1;
+	return this;
+    }
+    e = (NullExp *)copy();
+    e->committed = 1;
+    tb = t->toBasetype();
+    e->type = type->toBasetype();
+    if (tb != e->type)
+    {
+	// NULL implicitly converts to any pointer type or dynamic array
+	if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
+	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
+	     tb->ty == Tdelegate))
+	{
+#if 0
+	    if (tb->ty == Tdelegate)
+	    {   TypeDelegate *td = (TypeDelegate *)tb;
+		TypeFunction *tf = (TypeFunction *)td->nextOf();
+
+		if (!tf->varargs &&
+		    !(tf->arguments && tf->arguments->dim)
+		   )
+		{
+		    return Expression::castTo(sc, t);
+		}
+	    }
+#endif
+	}
+	else
+	{
+	    return e->Expression::castTo(sc, t);
+	}
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *StringExp::castTo(Scope *sc, Type *t)
+{
+    /* This follows copy-on-write; any changes to 'this'
+     * will result in a copy.
+     * The this->string member is considered immutable.
+     */
+    StringExp *se;
+    Type *tb;
+    int copied = 0;
+
+    //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
+
+    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+    {
+	error("cannot convert string literal to void*");
+    }
+
+    se = this;
+    if (!committed)
+    {   se = (StringExp *)copy();
+	se->committed = 1;
+	copied = 1;
+    }
+
+    if (type == t)
+    {
+	return se;
+    }
+
+    tb = t->toBasetype();
+    //printf("\ttype = %s\n", type->toChars());
+    if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
+	return Expression::castTo(sc, t);
+
+    Type *typeb = type->toBasetype();
+    if (typeb == tb)
+    {
+	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	se->type = t;
+	return se;
+    }
+
+    if (committed && tb->ty == Tsarray && typeb->ty == Tarray)
+    {
+	se = (StringExp *)copy();
+	se->sz = tb->nextOf()->size();
+	se->len = (len * sz) / se->sz;
+	se->committed = 1;
+	se->type = t;
+	return se;
+    }
+
+    if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+    {	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	goto Lcast;
+    }
+    if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
+    {	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	goto Lcast;
+    }
+
+    if (typeb->nextOf()->size() == tb->nextOf()->size())
+    {
+	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	if (tb->ty == Tsarray)
+	    goto L2;	// handle possible change in static array dimension
+	se->type = t;
+	return se;
+    }
+
+    if (committed)
+	goto Lcast;
+
+#define X(tf,tt)	((tf) * 256 + (tt))
+    {
+    OutBuffer buffer;
+    size_t newlen = 0;
+    int tfty = typeb->nextOf()->toBasetype()->ty;
+    int ttty = tb->nextOf()->toBasetype()->ty;
+    switch (X(tfty, ttty))
+    {
+	case X(Tchar, Tchar):
+	case X(Twchar,Twchar):
+	case X(Tdchar,Tdchar):
+	    break;
+
+	case X(Tchar, Twchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF16(c);
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	case X(Tchar, Tdchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Twchar,Tchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF8(c);
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Twchar,Tdchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Tdchar,Tchar):
+	    for (size_t u = 0; u < len; u++)
+	    {
+		unsigned c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF8(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Tdchar,Twchar):
+	    for (size_t u = 0; u < len; u++)
+	    {
+		unsigned c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF16(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	L1:
+	    if (!copied)
+	    {   se = (StringExp *)copy();
+		copied = 1;
+	    }
+	    se->string = buffer.extractData();
+	    se->len = newlen;
+	    se->sz = tb->nextOf()->size();
+	    break;
+
+	default:
+	    assert(typeb->nextOf()->size() != tb->nextOf()->size());
+	    goto Lcast;
+    }
+    }
+#undef X
+L2:
+    assert(copied);
+
+    // See if need to truncate or extend the literal
+    if (tb->ty == Tsarray)
+    {
+	int dim2 = ((TypeSArray *)tb)->dim->toInteger();
+
+	//printf("dim from = %d, to = %d\n", se->len, dim2);
+
+	// Changing dimensions
+	if (dim2 != se->len)
+	{
+	    // Copy when changing the string literal
+	    unsigned newsz = se->sz;
+	    void *s;
+	    int d;
+
+	    d = (dim2 < se->len) ? dim2 : se->len;
+	    s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
+	    memcpy(s, se->string, d * newsz);
+	    // Extend with 0, add terminating 0
+	    memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+	    se->string = s;
+	    se->len = dim2;
+	}
+    }
+    se->type = t;
+    return se;
+
+Lcast:
+    Expression *e = new CastExp(loc, se, t);
+    e->type = t;	// so semantic() won't be run on e
+    return e;
+}
+
+Expression *AddrExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+
+	if (e1->op == TOKoverloadset &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{   OverExp *eo = (OverExp *)e1;
+	    FuncDeclaration *f = NULL;
+	    for (int i = 0; i < eo->vars->a.dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
+		FuncDeclaration *f2 = s->isFuncDeclaration();
+		assert(f2);
+		if (f2->overloadExactMatch(t->nextOf(), m))
+		{   if (f)
+			/* Error if match in more than one overload set,
+			 * even if one is a 'better' match than the other.
+			 */
+			ScopeDsymbol::multiplyDefined(loc, f, f2);
+		    else
+			f = f2;
+		}
+	    }
+	    if (f)
+	    {	f->tookAddressOf++;
+		SymOffExp *se = new SymOffExp(loc, f, 0, 0);
+		se->semantic(sc);
+		// Let SymOffExp::castTo() do the heavy lifting
+		return se->castTo(sc, t);
+	    }
+	}
+
+
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    VarExp *ve = (VarExp *)e1;
+	    FuncDeclaration *f = ve->var->isFuncDeclaration();
+	    if (f)
+	    {
+		assert(0);	// should be SymOffExp instead
+		f = f->overloadExactMatch(tb->nextOf(), m);
+		if (f)
+		{
+		    e = new VarExp(loc, f);
+		    e->type = f->type;
+		    e = new AddrExp(loc, e);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+
+Expression *TupleExp::castTo(Scope *sc, Type *t)
+{   TupleExp *e = (TupleExp *)copy();
+    e->exps = (Expressions *)exps->copy();
+    for (size_t i = 0; i < e->exps->dim; i++)
+    {   Expression *ex = (Expression *)e->exps->data[i];
+	ex = ex->castTo(sc, t);
+	e->exps->data[i] = (void *)ex;
+    }
+    return e;
+}
+
+
+Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t)
+	return this;
+    ArrayLiteralExp *e = this;
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
+	// Not trying to convert non-void[] to void[]
+	!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		goto L1;
+	}
+
+	e = (ArrayLiteralExp *)copy();
+	e->elements = (Expressions *)elements->copy();
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *ex = (Expression *)elements->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->elements->data[i] = (void *)ex;
+	}
+	e->type = t;
+	return e;
+    }
+    if (tb->ty == Tpointer && typeb->ty == Tsarray)
+    {
+	Type *tp = typeb->nextOf()->pointerTo();
+	if (!tp->equals(e->type))
+	{   e = (ArrayLiteralExp *)copy();
+	    e->type = tp;
+	}
+    }
+L1:
+    return e->Expression::castTo(sc, t);
+}
+
+Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    if (type == t)
+	return this;
+    AssocArrayLiteralExp *e = this;
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray &&
+	tb->nextOf()->toBasetype()->ty != Tvoid)
+    {
+	e = (AssocArrayLiteralExp *)copy();
+	e->keys = (Expressions *)keys->copy();
+	e->values = (Expressions *)values->copy();
+	assert(keys->dim == values->dim);
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *ex = (Expression *)values->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->values->data[i] = (void *)ex;
+
+	    ex = (Expression *)keys->data[i];
+	    ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
+	    e->keys->data[i] = (void *)ex;
+	}
+	e->type = t;
+	return e;
+    }
+L1:
+    return e->Expression::castTo(sc, t);
+}
+
+Expression *SymOffExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t && hasOverloads == 0)
+	return this;
+    Expression *e;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (hasOverloads &&
+	    typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
+	    (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->nextOf(), m);
+		if (f)
+		{
+		    if (tb->ty == Tdelegate && f->needThis() && hasThis(sc))
+		    {
+			e = new DelegateExp(loc, new ThisExp(loc), f);
+			e = e->semantic(sc);
+		    }
+		    else if (tb->ty == Tdelegate && f->isNested())
+		    {
+			e = new DelegateExp(loc, new IntegerExp(0), f);
+			e = e->semantic(sc);
+		    }
+		    else
+		    {
+			e = new SymOffExp(loc, f, 0);
+			e->type = t;
+		    }
+		    f->tookAddressOf++;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	e = copy();
+	e->type = t;
+	((SymOffExp *)e)->hasOverloads = 0;
+    }
+    return e;
+}
+
+Expression *DelegateExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    static char msg[] = "cannot form delegate due to covariant return type";
+
+    Expression *e = this;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Look for delegates to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction &&
+	    tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction)
+	{
+	    if (func)
+	    {
+		f = func->overloadExactMatch(tb->nextOf(), m);
+		if (f)
+		{   int offset;
+		    if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
+			error("%s", msg);
+		    f->tookAddressOf++;
+		    e = new DelegateExp(loc, e1, f);
+		    e->type = t;
+		    return e;
+		}
+		if (func->tintro)
+		    error("%s", msg);
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	int offset;
+
+	func->tookAddressOf++;
+	if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset)
+	    error("%s", msg);
+	e = copy();
+	e->type = t;
+    }
+    return e;
+}
+
+Expression *CondExp::castTo(Scope *sc, Type *t)
+{
+    Expression *e = this;
+
+    if (type != t)
+    {
+	if (1 || e1->op == TOKstring || e2->op == TOKstring)
+	{   e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *BinExp::scaleFactor(Scope *sc)
+{   d_uns64 stride;
+    Type *t1b = e1->type->toBasetype();
+    Type *t2b = e2->type->toBasetype();
+
+    if (t1b->ty == Tpointer && t2b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (ptr + int) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+
+	stride = t1b->nextOf()->size(loc);
+	if (!t->equals(t2b))
+	    e2 = e2->castTo(sc, t);
+	e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
+	e2->type = t;
+	type = e1->type;
+    }
+    else if (t2b->ty == Tpointer && t1b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (int + ptr) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+	Expression *e;
+
+	stride = t2b->nextOf()->size(loc);
+	if (!t->equals(t1b))
+	    e = e1->castTo(sc, t);
+	else
+	    e = e1;
+	e = new MulExp(loc, e, new IntegerExp(0, stride, t));
+	e->type = t;
+	type = e2->type;
+	e1 = e2;
+	e2 = e;
+    }
+    return this;
+}
+
+/**************************************
+ * Combine types.
+ * Output:
+ *	*pt	merged type, if *pt is not NULL
+ *	*pe1	rewritten e1
+ *	*pe2	rewritten e2
+ * Returns:
+ *	!=0	success
+ *	0	failed
+ */
+
+int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
+{
+    //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
+    //dump(0);
+
+    Expression *e1 = (*pe1)->integralPromotions(sc);
+    Expression *e2 = (*pe2)->integralPromotions(sc);
+
+    Type *t1 = e1->type;
+    Type *t2 = e2->type;
+    assert(t1);
+    Type *t = t1;
+
+    //if (t1) printf("\tt1 = %s\n", t1->toChars());
+    //if (t2) printf("\tt2 = %s\n", t2->toChars());
+#ifdef DEBUG
+    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
+#endif
+    assert(t2);
+
+    Type *t1b = t1->toBasetype();
+    Type *t2b = t2->toBasetype();
+
+    TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+    {	TY ty1;
+	TY ty2;
+
+	ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
+	ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
+
+	if (t1b->ty == ty1)	// if no promotions
+	{
+	    if (t1 == t2)
+	    {
+		t = t1;
+		goto Lret;
+	    }
+
+	    if (t1b == t2b)
+	    {
+		t = t1b;
+		goto Lret;
+	    }
+	}
+
+	t = Type::basic[ty];
+
+	t1 = Type::basic[ty1];
+	t2 = Type::basic[ty2];
+	e1 = e1->castTo(sc, t1);
+	e2 = e2->castTo(sc, t2);
+	//printf("after typeCombine():\n");
+	//dump(0);
+	//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+	goto Lret;
+    }
+
+    t1 = t1b;
+    t2 = t2b;
+
+Lagain:
+    if (t1 == t2)
+    {
+    }
+    else if (t1->ty == Tpointer && t2->ty == Tpointer)
+    {
+	// Bring pointers to compatible type
+	Type *t1n = t1->nextOf();
+	Type *t2n = t2->nextOf();
+
+	if (t1n == t2n)
+	    ;
+	else if (t1n->ty == Tvoid)	// pointers to void are always compatible
+	    t = t2;
+	else if (t2n->ty == Tvoid)
+	    ;
+	else if (t1n->mod != t2n->mod)
+	{
+	    t1 = t1n->mutableOf()->constOf()->pointerTo();
+	    t2 = t2n->mutableOf()->constOf()->pointerTo();
+	    t = t1;
+	    goto Lagain;
+	}
+	else if (t1n->ty == Tclass && t2n->ty == Tclass)
+	{   ClassDeclaration *cd1 = t1n->isClassHandle();
+	    ClassDeclaration *cd2 = t2n->isClassHandle();
+	    int offset;
+
+	    if (cd1->isBaseOf(cd2, &offset))
+	    {
+		if (offset)
+		    e2 = e2->castTo(sc, t);
+	    }
+	    else if (cd2->isBaseOf(cd1, &offset))
+	    {
+		t = t2;
+		if (offset)
+		    e1 = e1->castTo(sc, t);
+	    }
+	    else
+		goto Lincompatible;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+	     e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid)
+    {	/*  (T[n] op void*)
+	 *  (T[] op void*)
+	 */
+	goto Lx1;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+	     e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid)
+    {	/*  (void* op T[n])
+	 *  (void* op T[])
+	 */
+	goto Lx2;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    /* If one is mutable and the other invariant, then retry
+     * with both of them as const
+     */
+    else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
+	     (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
+	     t1->nextOf()->mod != t2->nextOf()->mod
+	    )
+    {
+	if (t1->ty == Tpointer)
+	    t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo();
+	else
+	    t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf();
+
+	if (t2->ty == Tpointer)
+	    t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo();
+	else
+	    t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf();
+	t = t1;
+	goto Lagain;
+    }
+    else if (t1->ty == Tclass || t2->ty == Tclass)
+    {
+	while (1)
+	{
+	    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;
+	    }
+	    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 = tc2->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 (t1->ty == Tstruct && t2->ty == Tstruct)
+    {
+	if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym)
+	    goto Lincompatible;
+    }
+    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e2->implicitConvTo(t1->nextOf()->arrayOf()))
+    {
+     Lx1:
+	t = t1->nextOf()->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e1->implicitConvTo(t2->nextOf()->arrayOf()))
+    {
+     Lx2:
+	t = t2->nextOf()->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->isintegral() && t2->isintegral())
+    {
+	assert(0);
+    }
+    else if (e1->op == TOKslice && t1->ty == Tarray &&
+	     e2->implicitConvTo(t1->nextOf()))
+    {	// T[] op T
+	e2 = e2->castTo(sc, t1->nextOf());
+	t = t1->nextOf()->arrayOf();
+    }
+    else if (e2->op == TOKslice && t2->ty == Tarray &&
+	     e1->implicitConvTo(t2->nextOf()))
+    {	// T op T[]
+	e1 = e1->castTo(sc, t2->nextOf());
+	t = t2->nextOf()->arrayOf();
+
+	//printf("test %s\n", e->toChars());
+	e1 = e1->optimize(WANTvalue);
+	if (e && e->isCommutative() && e1->isConst())
+	{   /* Swap operands to minimize number of functions generated
+	     */
+	    //printf("swap %s\n", e->toChars());
+	    Expression *tmp = e1;
+	    e1 = e2;
+	    e2 = tmp;
+	}
+    }
+    else
+    {
+     Lincompatible:
+	return 0;
+    }
+Lret:
+    if (!*pt)
+	*pt = t;
+    *pe1 = e1;
+    *pe2 = e2;
+#if 0
+    printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
+    if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
+    if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
+    printf("\ttype = %s\n", t->toChars());
+#endif
+    //dump(0);
+    return 1;
+
+
+Lt1:
+    e2 = e2->castTo(sc, t1);
+    t = t1;
+    goto Lret;
+
+Lt2:
+    e1 = e1->castTo(sc, t2);
+    t = t2;
+    goto Lret;
+}
+
+/************************************
+ * Bring leaves to common type.
+ */
+
+Expression *BinExp::typeCombine(Scope *sc)
+{
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+
+    if (op == TOKmin || op == TOKadd)
+    {
+	if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass))
+	    goto Lerror;
+    }
+
+    if (!typeMerge(sc, this, &type, &e1, &e2))
+	goto Lerror;
+    return this;
+
+Lerror:
+    incompatibleTypes();
+    type = Type::terror;
+    e1 = new ErrorExp();
+    e2 = new ErrorExp();
+    return this;
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *Expression::integralPromotions(Scope *sc)
+{
+    Expression *e = this;
+
+    //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
+    switch (type->toBasetype()->ty)
+    {
+	case Tvoid:
+	    error("void has no value");
+	    break;
+
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:
+	case Tbit:
+	case Tbool:
+	case Tchar:
+	case Twchar:
+	    e = e->castTo(sc, Type::tint32);
+	    break;
+
+	case Tdchar:
+	    e = e->castTo(sc, Type::tuns32);
+	    break;
+    }
+    return e;
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality. Return !=0 if so.
+ * If they are arrays, but incompatible, issue error.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+
+int arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
+{
+    t1 = t1->toBasetype();
+    t2 = t2->toBasetype();
+
+    if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+	(t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
+    {
+	if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
+	    t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
+	    (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
+	{
+	    error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
+	}
+	return 1;
+    }
+    return 0;
+}
--- a/dmd2/class.c	Thu May 28 00:07:21 2009 +0200
+++ b/dmd2/class.c	Sat May 30 17:23:32 2009 +0100
@@ -1,1420 +1,1434 @@
-
-// 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 <stdlib.h>
-#include <assert.h>
-
-#include "root.h"
-#include "mem.h"
-
-#include "enum.h"
-#include "init.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-#include "mtype.h"
-#include "scope.h"
-#include "module.h"
-#include "expression.h"
-#include "statement.h"
-
-/********************************* ClassDeclaration ****************************/
-
-ClassDeclaration *ClassDeclaration::classinfo;
-ClassDeclaration *ClassDeclaration::object;
-
-ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
-    : AggregateDeclaration(loc, id)
-{
-    static char msg[] = "only object.d can define this reserved class name";
-
-    if (baseclasses)
-	this->baseclasses = *baseclasses;
-    baseClass = NULL;
-
-    interfaces_dim = 0;
-    interfaces = NULL;
-
-    vtblInterfaces = NULL;
-
-    //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim);
-
-    // For forward references
-    type = new TypeClass(this);
-    handle = type;
-
-    staticCtor = NULL;
-    staticDtor = NULL;
-
-    vtblsym = NULL;
-    vclassinfo = NULL;
-
-    if (id)
-    {	// Look for special class names
-
-	if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof)
-	    error("illegal class name");
-
-	// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
-	if (id->toChars()[0] == 'T')
-	{
-	    if (id == Id::TypeInfo)
-	    {	if (Type::typeinfo)
-		    Type::typeinfo->error("%s", msg);
-		Type::typeinfo = this;
-	    }
-
-	    if (id == Id::TypeInfo_Class)
-	    {	if (Type::typeinfoclass)
-		    Type::typeinfoclass->error("%s", msg);
-		Type::typeinfoclass = this;
-	    }
-
-	    if (id == Id::TypeInfo_Interface)
-	    {	if (Type::typeinfointerface)
-		    Type::typeinfointerface->error("%s", msg);
-		Type::typeinfointerface = this;
-	    }
-
-	    if (id == Id::TypeInfo_Struct)
-	    {	if (Type::typeinfostruct)
-		    Type::typeinfostruct->error("%s", msg);
-		Type::typeinfostruct = this;
-	    }
-
-	    if (id == Id::TypeInfo_Typedef)
-	    {	if (Type::typeinfotypedef)
-		    Type::typeinfotypedef->error("%s", msg);
-		Type::typeinfotypedef = this;
-	    }
-
-	    if (id == Id::TypeInfo_Pointer)
-	    {	if (Type::typeinfopointer)
-		    Type::typeinfopointer->error("%s", msg);
-		Type::typeinfopointer = this;
-	    }
-
-	    if (id == Id::TypeInfo_Array)
-	    {	if (Type::typeinfoarray)
-		    Type::typeinfoarray->error("%s", msg);
-		Type::typeinfoarray = this;
-	    }
-
-	    if (id == Id::TypeInfo_StaticArray)
-	    {	//if (Type::typeinfostaticarray)
-		    //Type::typeinfostaticarray->error("%s", msg);
-		Type::typeinfostaticarray = this;
-	    }
-
-	    if (id == Id::TypeInfo_AssociativeArray)
-	    {	if (Type::typeinfoassociativearray)
-		    Type::typeinfoassociativearray->error("%s", msg);
-		Type::typeinfoassociativearray = this;
-	    }
-
-	    if (id == Id::TypeInfo_Enum)
-	    {	if (Type::typeinfoenum)
-		    Type::typeinfoenum->error("%s", msg);
-		Type::typeinfoenum = this;
-	    }
-
-	    if (id == Id::TypeInfo_Function)
-	    {	if (Type::typeinfofunction)
-		    Type::typeinfofunction->error("%s", msg);
-		Type::typeinfofunction = this;
-	    }
-
-	    if (id == Id::TypeInfo_Delegate)
-	    {	if (Type::typeinfodelegate)
-		    Type::typeinfodelegate->error("%s", msg);
-		Type::typeinfodelegate = this;
-	    }
-
-	    if (id == Id::TypeInfo_Tuple)
-	    {	if (Type::typeinfotypelist)
-		    Type::typeinfotypelist->error("%s", msg);
-		Type::typeinfotypelist = this;
-	    }
-
-#if DMDV2
-	    if (id == Id::TypeInfo_Const)
-	    {	if (Type::typeinfoconst)
-		    Type::typeinfoconst->error("%s", msg);
-		Type::typeinfoconst = this;
-	    }
-
-	    if (id == Id::TypeInfo_Invariant)
-	    {	if (Type::typeinfoinvariant)
-		    Type::typeinfoinvariant->error("%s", msg);
-		Type::typeinfoinvariant = this;
-	    }
-#endif
-	}
-
-	if (id == Id::Object)
-	{   if (object)
-		object->error("%s", msg);
-	    object = this;
-	}
-
-	if (id == Id::ClassInfo)
-	{   if (classinfo)
-		classinfo->error("%s", msg);
-	    classinfo = this;
-	}
-
-	if (id == Id::ModuleInfo)
-	{   if (Module::moduleinfo)
-		Module::moduleinfo->error("%s", msg);
-	    Module::moduleinfo = this;
-	}
-    }
-
-    com = 0;
-    isauto = 0;
-    isabstract = 0;
-    isnested = 0;
-    vthis = NULL;
-    inuse = 0;
-}
-
-Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
-{
-    ClassDeclaration *cd;
-
-    //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
-    if (s)
-	cd = (ClassDeclaration *)s;
-    else
-	cd = new ClassDeclaration(loc, ident, NULL);
-
-    cd->storage_class |= storage_class;
-
-    cd->baseclasses.setDim(this->baseclasses.dim);
-    for (int i = 0; i < cd->baseclasses.dim; i++)
-    {
-	BaseClass *b = (BaseClass *)this->baseclasses.data[i];
-	BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
-	cd->baseclasses.data[i] = b2;
-    }
-
-    ScopeDsymbol::syntaxCopy(cd);
-    return cd;
-}
-
-void ClassDeclaration::semantic(Scope *sc)
-{   int i;
-    unsigned offset;
-
-    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
-    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
-    //printf("sc->stc = %x\n", sc->stc);
-
-    //{ static int n;  if (++n == 20) *(char*)0=0; }
-
-    if (!ident)		// if anonymous class
-    {	const char *id = "__anonclass";
-
-	ident = Identifier::generateId(id);
-    }
-
-    if (!scope)
-    {
-	if (!parent && sc->parent && !sc->parent->isModule())
-	    parent = sc->parent;
-
-	type = type->semantic(loc, sc);
-	handle = handle->semantic(loc, sc);
-    }
-    if (!members)			// if forward reference
-    {	//printf("\tclass '%s' is forward referenced\n", toChars());
-	return;
-    }
-    if (symtab)
-    {	if (!scope)
-	{   //printf("\tsemantic for '%s' is already completed\n", toChars());
-	    return;		// semantic() already completed
-	}
-    }
-    else
-	symtab = new DsymbolTable();
-
-    Scope *scx = NULL;
-    if (scope)
-    {	sc = scope;
-	scx = scope;		// save so we don't make redundant copies
-	scope = NULL;
-    }
-#ifdef IN_GCC
-    methods.setDim(0);
-#endif
-
-    if (sc->stc & STCdeprecated)
-    {
-	isdeprecated = 1;
-    }
-
-    if (sc->linkage == LINKcpp)
-	error("cannot create C++ classes");
-
-    // Expand any tuples in baseclasses[]
-    for (i = 0; i < baseclasses.dim; )
-    {	BaseClass *b = (BaseClass *)baseclasses.data[i];
-	b->type = b->type->semantic(loc, sc);
-	Type *tb = b->type->toBasetype();
-
-	if (tb->ty == Ttuple)
-	{   TypeTuple *tup = (TypeTuple *)tb;
-	    enum PROT protection = b->protection;
-	    baseclasses.remove(i);
-	    size_t dim = Argument::dim(tup->arguments);
-	    for (size_t j = 0; j < dim; j++)
-	    {	Argument *arg = Argument::getNth(tup->arguments, j);
-		b = new BaseClass(arg->type, protection);
-		baseclasses.insert(i + j, b);
-	    }
-	}
-	else
-	    i++;
-    }
-
-    // See if there's a base class as first in baseclasses[]
-    if (baseclasses.dim)
-    {	TypeClass *tc;
-	BaseClass *b;
-	Type *tb;
-
-	b = (BaseClass *)baseclasses.data[0];
-	//b->type = b->type->semantic(loc, sc);
-	tb = b->type->toBasetype();
-	if (tb->ty != Tclass)
-	{   error("base type must be class or interface, not %s", b->type->toChars());
-	    baseclasses.remove(0);
-	}
-	else
-	{
-	    tc = (TypeClass *)(tb);
-
-	    if (tc->sym->isDeprecated())
-	    {
-		if (!isDeprecated())
-		{
-		    // Deriving from deprecated class makes this one deprecated too
-		    isdeprecated = 1;
-
-		    tc->checkDeprecated(loc, sc);
-		}
-	    }
-
-	    if (tc->sym->isInterfaceDeclaration())
-		;
-	    else
-	    {
-		for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
-		{
-		    if (cdb == this)
-		    {
-			error("circular inheritance");
-			baseclasses.remove(0);
-			goto L7;
-		    }
-		}
-		if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0)
-		{
-		    //error("forward reference of base class %s", baseClass->toChars());
-		    // Forward reference of base class, try again later
-		    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
-		    scope = scx ? scx : new Scope(*sc);
-		    scope->setNoFree();
-		    scope->module->addDeferredSemantic(this);
-		    return;
-		}
-		else
-		{   baseClass = tc->sym;
-		    b->base = baseClass;
-		}
-	     L7: ;
-	    }
-	}
-    }
-
-    // Treat the remaining entries in baseclasses as interfaces
-    // Check for errors, handle forward references
-    for (i = (baseClass ? 1 : 0); i < baseclasses.dim; )
-    {	TypeClass *tc;
-	BaseClass *b;
-	Type *tb;
-
-	b = (BaseClass *)baseclasses.data[i];
-	b->type = b->type->semantic(loc, sc);
-	tb = b->type->toBasetype();
-	if (tb->ty == Tclass)
-	    tc = (TypeClass *)tb;
-	else
-	    tc = NULL;
-	if (!tc || !tc->sym->isInterfaceDeclaration())
-	{
-	    error("base type must be interface, not %s", b->type->toChars());
-	    baseclasses.remove(i);
-	    continue;
-	}
-	else
-	{
-	    if (tc->sym->isDeprecated())
-	    {
-		if (!isDeprecated())
-		{
-		    // Deriving from deprecated class makes this one deprecated too
-		    isdeprecated = 1;
-
-		    tc->checkDeprecated(loc, sc);
-		}
-	    }
-
-	    // Check for duplicate interfaces
-	    for (size_t j = (baseClass ? 1 : 0); j < i; j++)
-	    {
-		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
-		if (b2->base == tc->sym)
-		    error("inherits from duplicate interface %s", b2->base->toChars());
-	    }
-
-	    b->base = tc->sym;
-	    if (!b->base->symtab || b->base->scope)
-	    {
-		//error("forward reference of base class %s", baseClass->toChars());
-		// Forward reference of base, try again later
-		//printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
-		scope = scx ? scx : new Scope(*sc);
-		scope->setNoFree();
-		scope->module->addDeferredSemantic(this);
-		return;
-	    }
-	}
-	i++;
-    }
-
-
-    // If no base class, and this is not an Object, use Object as base class
-    if (!baseClass && ident != Id::Object)
-    {
-	// BUG: what if Object is redefined in an inner scope?
-	Type *tbase = new TypeIdentifier(0, Id::Object);
-	BaseClass *b;
-	TypeClass *tc;
-	Type *bt;
-
-	if (!object)
-	{
-	    error("missing or corrupt object.d");
-	    fatal();
-	}
-	bt = tbase->semantic(loc, sc)->toBasetype();
-	b = new BaseClass(bt, PROTpublic);
-	baseclasses.shift(b);
-	assert(b->type->ty == Tclass);
-	tc = (TypeClass *)(b->type);
-	baseClass = tc->sym;
-	assert(!baseClass->isInterfaceDeclaration());
-	b->base = baseClass;
-    }
-
-    interfaces_dim = baseclasses.dim;
-    interfaces = (BaseClass **)baseclasses.data;
-
-
-    if (baseClass)
-    {
-	if (baseClass->storage_class & STCfinal)
-	    error("cannot inherit from final class %s", baseClass->toChars());
-
-	interfaces_dim--;
-	interfaces++;
-
-	// Copy vtbl[] from base class
-	vtbl.setDim(baseClass->vtbl.dim);
-	memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim);
-
-	// Inherit properties from base class
-	com = baseClass->isCOMclass();
-	isauto = baseClass->isauto;
-	vthis = baseClass->vthis;
-	storage_class |= baseClass->storage_class & (STCconst | STCinvariant);
-    }
-    else
-    {
-	// No base class, so this is the root of the class hierarchy
-	vtbl.setDim(0);
-	vtbl.push(this);		// leave room for classinfo as first member
-    }
-
-    protection = sc->protection;
-    storage_class |= sc->stc;
-
-    if (sizeok == 0)
-    {
-	interfaceSemantic(sc);
-
-	for (i = 0; i < members->dim; i++)
-	{
-	    Dsymbol *s = (Dsymbol *)members->data[i];
-	    s->addMember(sc, this, 1);
-	}
-
-	/* If this is a nested class, add the hidden 'this'
-	 * member which is a pointer to the enclosing scope.
-	 */
-	if (vthis)		// if inheriting from nested class
-	{   // Use the base class's 'this' member
-	    isnested = 1;
-	    if (storage_class & STCstatic)
-		error("static class cannot inherit from nested class %s", baseClass->toChars());
-	    if (toParent2() != baseClass->toParent2())
-	    {
-		if (toParent2())
-		{
-		    error("is nested within %s, but super class %s is nested within %s",
-			toParent2()->toChars(),
-			baseClass->toChars(),
-			baseClass->toParent2()->toChars());
-		}
-		else
-		{
-		    error("is not nested, but super class %s is nested within %s",
-			baseClass->toChars(),
-			baseClass->toParent2()->toChars());
-		}
-		isnested = 0;
-	    }
-	}
-	else if (!(storage_class & STCstatic))
-	{   Dsymbol *s = toParent2();
-	    if (s)
-	    {
-		ClassDeclaration *cd = s->isClassDeclaration();
-		FuncDeclaration *fd = s->isFuncDeclaration();
-
-
-		if (cd || fd)
-		{   isnested = 1;
-		    Type *t;
-		    if (cd)
-			t = cd->type;
-		    else if (fd)
-		    {	AggregateDeclaration *ad = fd->isMember2();
-			if (ad)
-			    t = ad->handle;
-			else
-			{
-			    t = new TypePointer(Type::tvoid);
-			    t = t->semantic(0, sc);
-			}
-		    }
-		    else
-			assert(0);
-		    assert(!vthis);
-		    vthis = new ThisDeclaration(t);
-		    members->push(vthis);
-		}
-	    }
-	}
-    }
-
-    if (storage_class & (STCauto | STCscope))
-	isauto = 1;
-    if (storage_class & STCabstract)
-	isabstract = 1;
-    if (storage_class & STCinvariant)
-	type = type->invariantOf();
-    else if (storage_class & STCconst)
-	type = type->constOf();
-
-    sc = sc->push(this);
-    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
-		 STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
-    sc->stc |= storage_class & (STCconst | STCinvariant);
-    sc->parent = this;
-    sc->inunion = 0;
-
-    if (isCOMclass())
-	sc->linkage = LINKwindows;
-    sc->protection = PROTpublic;
-    sc->explicitProtection = 0;
-    sc->structalign = 8;
-    structalign = sc->structalign;
-    if (baseClass)
-    {	sc->offset = baseClass->structsize;
-	alignsize = baseClass->alignsize;
-//	if (isnested)
-//	    sc->offset += PTRSIZE;	// room for uplevel context pointer
-    }
-    else
-    {	sc->offset = PTRSIZE * 2;	// allow room for __vptr and __monitor
-	alignsize = PTRSIZE;
-    }
-    structsize = sc->offset;
-    Scope scsave = *sc;
-    int members_dim = members->dim;
-    sizeok = 0;
-    for (i = 0; i < members_dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	s->semantic(sc);
-    }
-
-    if (sizeok == 2)
-    {	// semantic() failed because of forward references.
-	// Unwind what we did, and defer it for later
-	fields.setDim(0);
-	structsize = 0;
-	alignsize = 0;
-	structalign = 0;
-
-	sc = sc->pop();
-
-	scope = scx ? scx : new Scope(*sc);
-	scope->setNoFree();
-	scope->module->addDeferredSemantic(this);
-
-	//printf("\tsemantic('%s') failed due to forward references\n", toChars());
-	return;
-    }
-
-    //printf("\tsemantic('%s') successful\n", toChars());
-
-    structsize = sc->offset;
-    //members->print();
-
-    /* Look for special member functions.
-     * They must be in this class, not in a base class.
-     */
-    ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
-    if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration()))
-	ctor = NULL;
-
-//    dtor = (DtorDeclaration *)search(Id::dtor, 0);
-//    if (dtor && dtor->toParent() != this)
-//	dtor = NULL;
-
-//    inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
-//    if (inv && inv->toParent() != this)
-//	inv = NULL;
-
-    // Can be in base class
-    aggNew    = (NewDeclaration *)search(0, Id::classNew, 0);
-    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
-
-    // If this class has no constructor, but base class does, create
-    // a constructor:
-    //    this() { }
-    if (!ctor && baseClass && baseClass->ctor)
-    {
-	//printf("Creating default this(){} for class %s\n", toChars());
-	ctor = new CtorDeclaration(loc, 0, NULL, 0);
-	ctor->fbody = new CompoundStatement(0, new Statements());
-	members->push(ctor);
-	ctor->addMember(sc, this, 1);
-	*sc = scsave;	// why? What about sc->nofree?
-	sc->offset = structsize;
-	ctor->semantic(sc);
-	defaultCtor = ctor;
-    }
-
-#if 0
-    if (baseClass)
-    {	if (!aggDelete)
-	    aggDelete = baseClass->aggDelete;
-	if (!aggNew)
-	    aggNew = baseClass->aggNew;
-    }
-#endif
-
-    // Allocate instance of each new interface
-    for (i = 0; i < vtblInterfaces->dim; i++)
-    {
-	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
-	unsigned thissize = PTRSIZE;
-
-	alignmember(structalign, thissize, &sc->offset);
-	assert(b->offset == 0);
-	b->offset = sc->offset;
-
-	// Take care of single inheritance offsets
-	while (b->baseInterfaces_dim)
-	{
-	    b = &b->baseInterfaces[0];
-	    b->offset = sc->offset;
-	}
-
-	sc->offset += thissize;
-	if (alignsize < thissize)
-	    alignsize = thissize;
-    }
-    structsize = sc->offset;
-    sizeok = 1;
-    Module::dprogress++;
-
-    dtor = buildDtor(sc);
-
-    sc->pop();
-
-#if 0 // Do not call until toObjfile() because of forward references
-    // Fill in base class vtbl[]s
-    for (i = 0; i < vtblInterfaces->dim; i++)
-    {
-	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
-
-	//b->fillVtbl(this, &b->vtbl, 1);
-    }
-#endif
-    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
-}
-
-void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    if (!isAnonymous())
-    {
-	buf->printf("%s ", kind());
-	buf->writestring(toChars());
-	if (baseclasses.dim)
-	    buf->writestring(" : ");
-    }
-    for (int i = 0; i < baseclasses.dim; i++)
-    {
-	BaseClass *b = (BaseClass *)baseclasses.data[i];
-
-	if (i)
-	    buf->writeByte(',');
-	//buf->writestring(b->base->ident->toChars());
-	b->type->toCBuffer(buf, NULL, hgs);
-    }
-    buf->writenl();
-    buf->writeByte('{');
-    buf->writenl();
-    for (int i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-
-	buf->writestring("    ");
-	s->toCBuffer(buf, hgs);
-    }
-    buf->writestring("}");
-    buf->writenl();
-}
-
-#if 0
-void ClassDeclaration::defineRef(Dsymbol *s)
-{
-    ClassDeclaration *cd;
-
-    AggregateDeclaration::defineRef(s);
-    cd = s->isClassDeclaration();
-    baseType = cd->baseType;
-    cd->baseType = NULL;
-}
-#endif
-
-/*********************************************
- * Determine if 'this' is a base class of cd.
- * This is used to detect circular inheritance only.
- */
-
-int ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
-{
-    if (!cd)
-	return 0;
-    //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
-    for (int i = 0; i < cd->baseclasses.dim; i++)
-    {	BaseClass *b = (BaseClass *)cd->baseclasses.data[i];
-
-	if (b->base == this || isBaseOf2(b->base))
-	    return 1;
-    }
-    return 0;
-}
-
-/*******************************************
- * Determine if 'this' is a base class of cd.
- */
-
-int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
-{
-    //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
-    if (poffset)
-	*poffset = 0;
-    while (cd)
-    {
-	if (this == cd->baseClass)
-	    return 1;
-
-	/* cd->baseClass might not be set if cd is forward referenced.
-	 */
-	if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
-	{
-	    cd->error("base class is forward referenced by %s", toChars());
-	}
-
-	cd = cd->baseClass;
-    }
-    return 0;
-}
-
-Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
-{
-    Dsymbol *s;
-
-    //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
-    if (scope)
-	semantic(scope);
-
-    if (!members || !symtab || scope)
-    {	error("is forward referenced when looking for '%s'", ident->toChars());
-	//*(char*)0=0;
-	return NULL;
-    }
-
-    s = ScopeDsymbol::search(loc, ident, flags);
-    if (!s)
-    {
-	// Search bases classes in depth-first, left to right order
-
-	int i;
-
-	for (i = 0; i < baseclasses.dim; i++)
-	{
-	    BaseClass *b = (BaseClass *)baseclasses.data[i];
-
-	    if (b->base)
-	    {
-		if (!b->base->symtab)
-		    error("base %s is forward referenced", b->base->ident->toChars());
-		else
-		{
-		    s = b->base->search(loc, ident, flags);
-		    if (s == this)	// happens if s is nested in this and derives from this
-			s = NULL;
-		    else if (s)
-			break;
-		}
-	    }
-	}
-    }
-    return s;
-}
-
-/**********************************************************
- * fd is in the vtbl[] for this class.
- * Return 1 if function is hidden (not findable through search).
- */
-
-#if DMDV2
-int isf(void *param, FuncDeclaration *fd)
-{
-    //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
-    return param == fd;
-}
-
-int ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
-{
-    //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars());
-    Dsymbol *s = search(0, fd->ident, 4|2);
-    if (!s)
-    {	//printf("not found\n");
-	/* Because, due to a hack, if there are multiple definitions
-	 * of fd->ident, NULL is returned.
-	 */
-	return 0;
-    }
-    s = s->toAlias();
-    OverloadSet *os = s->isOverloadSet();
-    if (os)
-    {
-	for (int i = 0; i < os->a.dim; i++)
-	{   Dsymbol *s = (Dsymbol *)os->a.data[i];
-	    FuncDeclaration *f2 = s->isFuncDeclaration();
-	    if (f2 && overloadApply(f2, &isf, fd))
-		return 0;
-	}
-	return 1;
-    }
-    else
-    {
-	FuncDeclaration *fdstart = s->isFuncDeclaration();
-	//printf("%s fdstart = %p\n", s->kind(), fdstart);
-	return !overloadApply(fdstart, &isf, fd);
-    }
-}
-#endif
-
-/****************
- * Find virtual function matching identifier and type.
- * Used to build virtual function tables for interface implementations.
- */
-
-FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
-{
-    //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
-
-    ClassDeclaration *cd = this;
-    Array *vtbl = &cd->vtbl;
-    while (1)
-    {
-	for (size_t i = 0; i < vtbl->dim; i++)
-	{
-	    FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i];
-
-	    //printf("\t[%d] = %s\n", i, fd->toChars());
-	    if (ident == fd->ident &&
-		//tf->equals(fd->type)
-		fd->type->covariant(tf) == 1
-	       )
-	    {   //printf("\t\tfound\n");
-		return fd;
-	    }
-	    //else printf("\t\t%d\n", fd->type->covariant(tf));
-	}
-	if (!cd)
-	    break;
-	vtbl = &cd->vtblFinal;
-	cd = cd->baseClass;
-    }
-
-    return NULL;
-}
-
-void ClassDeclaration::interfaceSemantic(Scope *sc)
-{
-    InterfaceDeclaration *id = isInterfaceDeclaration();
-
-    vtblInterfaces = new BaseClasses();
-    vtblInterfaces->reserve(interfaces_dim);
-
-    for (size_t i = 0; i < interfaces_dim; i++)
-    {
-	BaseClass *b = interfaces[i];
-
-	// If this is an interface, and it derives from a COM interface,
-	// then this is a COM interface too.
-	if (b->base->isCOMinterface())
-	    com = 1;
-
-	if (b->base->isCPPinterface() && id)
-	    id->cpp = 1;
-
-	vtblInterfaces->push(b);
-	b->copyBaseInterfaces(vtblInterfaces);
-    }
-}
-
-/****************************************
- */
-
-int ClassDeclaration::isCOMclass()
-{
-    return com;
-}
-
-int ClassDeclaration::isCOMinterface()
-{
-    return 0;
-}
-
-int ClassDeclaration::isCPPinterface()
-{
-    return 0;
-}
-
-
-/****************************************
- */
-
-int ClassDeclaration::isAbstract()
-{
-    if (isabstract)
-	return TRUE;
-    for (int i = 1; i < vtbl.dim; i++)
-    {
-	FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration();
-
-	//printf("\tvtbl[%d] = %p\n", i, fd);
-	if (!fd || fd->isAbstract())
-	{
-	    isabstract |= 1;
-	    return TRUE;
-	}
-    }
-    return FALSE;
-}
-
-
-/****************************************
- * Returns !=0 if there's an extra member which is the 'this'
- * pointer to the enclosing context (enclosing class or function)
- */
-
-int ClassDeclaration::isNested()
-{
-    return isnested;
-}
-
-/****************************************
- * Determine if slot 0 of the vtbl[] is reserved for something else.
- * For class objects, yes, this is where the classinfo ptr goes.
- * For COM interfaces, no.
- * For non-COM interfaces, yes, this is where the Interface ptr goes.
- */
-
-int ClassDeclaration::vtblOffset()
-{
-    return 1;
-}
-
-/****************************************
- */
-
-const char *ClassDeclaration::kind()
-{
-    return "class";
-}
-
-/****************************************
- */
-
-void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
-{
-    aclasses->push(this);
-}
-
-/********************************* InterfaceDeclaration ****************************/
-
-InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
-    : ClassDeclaration(loc, id, baseclasses)
-{
-    com = 0;
-    cpp = 0;
-    if (id == Id::IUnknown)	// IUnknown is the root of all COM interfaces
-    {	com = 1;
-	cpp = 1;		// IUnknown is also a C++ interface
-    }
-}
-
-Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
-{
-    InterfaceDeclaration *id;
-
-    if (s)
-	id = (InterfaceDeclaration *)s;
-    else
-	id = new InterfaceDeclaration(loc, ident, NULL);
-
-    ClassDeclaration::syntaxCopy(id);
-    return id;
-}
-
-void InterfaceDeclaration::semantic(Scope *sc)
-{   int i;
-
-    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
-    if (inuse)
-	return;
-    if (!scope)
-    {	type = type->semantic(loc, sc);
-	handle = handle->semantic(loc, sc);
-    }
-    if (!members)			// if forward reference
-    {	//printf("\tinterface '%s' is forward referenced\n", toChars());
-	return;
-    }
-    if (symtab)			// if already done
-    {	if (!scope)
-	    return;
-    }
-    else
-	symtab = new DsymbolTable();
-
-    Scope *scx = NULL;
-    if (scope)
-    {	sc = scope;
-	scx = scope;		// save so we don't make redundant copies
-	scope = NULL;
-    }
-
-    if (sc->stc & STCdeprecated)
-    {
-	isdeprecated = 1;
-    }
-
-    // Expand any tuples in baseclasses[]
-    for (i = 0; i < baseclasses.dim; )
-    {	BaseClass *b = (BaseClass *)baseclasses.data[0];
-	b->type = b->type->semantic(loc, sc);
-	Type *tb = b->type->toBasetype();
-
-	if (tb->ty == Ttuple)
-	{   TypeTuple *tup = (TypeTuple *)tb;
-	    enum PROT protection = b->protection;
-	    baseclasses.remove(i);
-	    size_t dim = Argument::dim(tup->arguments);
-	    for (size_t j = 0; j < dim; j++)
-	    {	Argument *arg = Argument::getNth(tup->arguments, j);
-		b = new BaseClass(arg->type, protection);
-		baseclasses.insert(i + j, b);
-	    }
-	}
-	else
-	    i++;
-    }
-
-    if (!baseclasses.dim && sc->linkage == LINKcpp)
-	cpp = 1;
-
-    // Check for errors, handle forward references
-    for (i = 0; i < baseclasses.dim; )
-    {	TypeClass *tc;
-	BaseClass *b;
-	Type *tb;
-
-	b = (BaseClass *)baseclasses.data[i];
-	b->type = b->type->semantic(loc, sc);
-	tb = b->type->toBasetype();
-	if (tb->ty == Tclass)
-	    tc = (TypeClass *)tb;
-	else
-	    tc = NULL;
-	if (!tc || !tc->sym->isInterfaceDeclaration())
-	{
-	    error("base type must be interface, not %s", b->type->toChars());
-	    baseclasses.remove(i);
-	    continue;
-	}
-	else
-	{
-	    // Check for duplicate interfaces
-	    for (size_t j = 0; j < i; j++)
-	    {
-		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
-		if (b2->base == tc->sym)
-		    error("inherits from duplicate interface %s", b2->base->toChars());
-	    }
-
-	    b->base = tc->sym;
-	    if (b->base == this || isBaseOf2(b->base))
-	    {
-		error("circular inheritance of interface");
-		baseclasses.remove(i);
-		continue;
-	    }
-	    if (!b->base->symtab || b->base->scope || b->base->inuse)
-	    {
-		//error("forward reference of base class %s", baseClass->toChars());
-		// Forward reference of base, try again later
-		//printf("\ttry later, forward reference of base %s\n", b->base->toChars());
-		scope = scx ? scx : new Scope(*sc);
-		scope->setNoFree();
-		scope->module->addDeferredSemantic(this);
-		return;
-	    }
-	}
-#if 0
-	// Inherit const/invariant from base class
-	storage_class |= b->base->storage_class & (STCconst | STCinvariant);
-#endif
-	i++;
-    }
-
-    interfaces_dim = baseclasses.dim;
-    interfaces = (BaseClass **)baseclasses.data;
-
-    interfaceSemantic(sc);
-
-    if (vtblOffset())
-	vtbl.push(this);		// leave room at vtbl[0] for classinfo
-
-    // Cat together the vtbl[]'s from base interfaces
-    for (i = 0; i < interfaces_dim; i++)
-    {	BaseClass *b = interfaces[i];
-
-	// Skip if b has already appeared
-	for (int k = 0; k < i; k++)
-	{
-	    if (b == interfaces[i])
-		goto Lcontinue;
-	}
-
-	// Copy vtbl[] from base class
-	if (b->base->vtblOffset())
-	{   int d = b->base->vtbl.dim;
-	    if (d > 1)
-	    {
-		vtbl.reserve(d - 1);
-		for (int j = 1; j < d; j++)
-		    vtbl.push(b->base->vtbl.data[j]);
-	    }
-	}
-	else
-	{
-	    vtbl.append(&b->base->vtbl);
-	}
-
-      Lcontinue:
-	;
-    }
-
-    protection = sc->protection;
-    storage_class |= sc->stc & (STCconst | STCinvariant);
-
-    for (i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	s->addMember(sc, this, 1);
-    }
-
-    sc = sc->push(this);
-    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
-                 STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
-    sc->stc |= storage_class & (STCconst | STCinvariant);
-    sc->parent = this;
-    if (isCOMinterface())
-	sc->linkage = LINKwindows;
-    else if (isCPPinterface())
-	sc->linkage = LINKcpp;
-    sc->structalign = 8;
-    structalign = sc->structalign;
-    sc->offset = PTRSIZE * 2;
-    inuse++;
-    for (i = 0; i < members->dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)members->data[i];
-	s->semantic(sc);
-    }
-    inuse--;
-    //members->print();
-    sc->pop();
-    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
-}
-
-
-/*******************************************
- * Determine if 'this' is a base class of cd.
- * (Actually, if it is an interface supported by cd)
- * Output:
- *	*poffset	offset to start of class
- *			OFFSET_RUNTIME	must determine offset at runtime
- * Returns:
- *	0	not a base
- *	1	is a base
- */
-
-int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
-{
-    unsigned j;
-
-    //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
-    assert(!baseClass);
-    for (j = 0; j < cd->interfaces_dim; j++)
-    {
-	BaseClass *b = cd->interfaces[j];
-
-	//printf("\tbase %s\n", b->base->toChars());
-	if (this == b->base)
-	{
-	    //printf("\tfound at offset %d\n", b->offset);
-	    if (poffset)
-	    {	*poffset = b->offset;
-		if (j && cd->isInterfaceDeclaration())
-		    *poffset = OFFSET_RUNTIME;
-	    }
-	    return 1;
-	}
-	if (isBaseOf(b, poffset))
-	{   if (j && poffset && cd->isInterfaceDeclaration())
-		*poffset = OFFSET_RUNTIME;
-	    return 1;
-	}
-    }
-
-    if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
-	return 1;
-
-    if (poffset)
-	*poffset = 0;
-    return 0;
-}
-
-
-int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
-{
-    //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
-    for (unsigned j = 0; j < bc->baseInterfaces_dim; j++)
-    {
-	BaseClass *b = &bc->baseInterfaces[j];
-
-	if (this == b->base)
-	{
-	    if (poffset)
-	    {	*poffset = b->offset;
-	    }
-	    return 1;
-	}
-	if (isBaseOf(b, poffset))
-	{
-	    return 1;
-	}
-    }
-    if (poffset)
-	*poffset = 0;
-    return 0;
-}
-
-/****************************************
- * Determine if slot 0 of the vtbl[] is reserved for something else.
- * For class objects, yes, this is where the ClassInfo ptr goes.
- * For COM interfaces, no.
- * For non-COM interfaces, yes, this is where the Interface ptr goes.
- */
-
-int InterfaceDeclaration::vtblOffset()
-{
-    if (isCOMinterface() || isCPPinterface())
-	return 0;
-    return 1;
-}
-
-int InterfaceDeclaration::isCOMinterface()
-{
-    return com;
-}
-
-int InterfaceDeclaration::isCPPinterface()
-{
-    return cpp;
-}
-
-/*******************************************
- */
-
-const char *InterfaceDeclaration::kind()
-{
-    return "interface";
-}
-
-
-/******************************** BaseClass *****************************/
-
-BaseClass::BaseClass()
-{
-    memset(this, 0, sizeof(BaseClass));
-}
-
-BaseClass::BaseClass(Type *type, enum PROT protection)
-{
-    //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
-    this->type = type;
-    this->protection = protection;
-    base = NULL;
-    offset = 0;
-
-    baseInterfaces_dim = 0;
-    baseInterfaces = NULL;
-}
-
-/****************************************
- * Fill in vtbl[] for base class based on member functions of class cd.
- * Input:
- *	vtbl		if !=NULL, fill it in
- *	newinstance	!=0 means all entries must be filled in by members
- *			of cd, not members of any base classes of cd.
- * Returns:
- *	!=0 if any entries were filled in by members of cd (not exclusively
- *	by base classes)
- */
-
-int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance)
-{
-    ClassDeclaration *id = base;
-    int j;
-    int result = 0;
-
-    //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
-    if (vtbl)
-	vtbl->setDim(base->vtbl.dim);
-
-    // first entry is ClassInfo reference
-    for (j = base->vtblOffset(); j < base->vtbl.dim; j++)
-    {
-	FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration();
-	FuncDeclaration *fd;
-	TypeFunction *tf;
-
-	//printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
-
-	assert(ifd);
-	// Find corresponding function in this class
-	tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
-	fd = cd->findFunc(ifd->ident, tf);
-	if (fd && !fd->isAbstract())
-	{
-	    //printf("            found\n");
-	    // Check that calling conventions match
-	    if (fd->linkage != ifd->linkage)
-		fd->error("linkage doesn't match interface function");
-
-	    // Check that it is current
-	    if (newinstance &&
-		fd->toParent() != cd &&
-		ifd->toParent() == base)
-		cd->error("interface function %s.%s is not implemented",
-		    id->toChars(), ifd->ident->toChars());
-
-	    if (fd->toParent() == cd)
-		result = 1;
-	}
-	else
-	{
-	    //printf("            not found\n");
-	    // BUG: should mark this class as abstract?
-	    if (!cd->isAbstract())
-		cd->error("interface function %s.%s isn't implemented",
-		    id->toChars(), ifd->ident->toChars());
-	    fd = NULL;
-	}
-	if (vtbl)
-	    vtbl->data[j] = fd;
-    }
-
-    return result;
-}
-
-void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
-{
-    //printf("+copyBaseInterfaces(), %s\n", base->toChars());
-//    if (baseInterfaces_dim)
-//	return;
-
-    baseInterfaces_dim = base->interfaces_dim;
-    baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass));
-
-    //printf("%s.copyBaseInterfaces()\n", base->toChars());
-    for (int i = 0; i < baseInterfaces_dim; i++)
-    {
-	BaseClass *b = &baseInterfaces[i];
-	BaseClass *b2 = base->interfaces[i];
-
-	assert(b2->vtbl.dim == 0);	// should not be filled yet
-	memcpy(b, b2, sizeof(BaseClass));
-
-	if (i)				// single inheritance is i==0
-	    vtblInterfaces->push(b);	// only need for M.I.
-	b->copyBaseInterfaces(vtblInterfaces);
-    }
-    //printf("-copyBaseInterfaces\n");
-}
+
+// 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 <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "rmem.h"
+
+#include "enum.h"
+#include "init.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "mtype.h"
+#include "scope.h"
+#include "module.h"
+#include "expression.h"
+#include "statement.h"
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::classinfo;
+ClassDeclaration *C