changeset 875:330f999ade44

Merged DMD 1.038
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 06 Jan 2009 16:33:51 +0100
parents 2ddee23bd70e
children 27a379f288bf
files dmd/attrib.c dmd/class.c dmd/cond.c dmd/doc.c dmd/expression.c dmd/expression.h dmd/func.c dmd/import.c dmd/interpret.c dmd/man.c dmd/mars.c dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/opover.c dmd/optimize.c dmd/statement.c dmd/statement.h dmd/template.c dmd/template.h gen/statements.cpp
diffstat 22 files changed, 4321 insertions(+), 3789 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/attrib.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/attrib.c	Tue Jan 06 16:33:51 2009 +0100
@@ -406,7 +406,7 @@
 }
 
 void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{   char *p;
+{   const char *p;
 
     switch (linkage)
     {
@@ -431,7 +431,7 @@
 
 char *LinkDeclaration::toChars()
 {
-    return "extern ()";
+    return (char *)"extern ()";
 }
 
 /********************************* ProtDeclaration ****************************/
@@ -476,7 +476,7 @@
 }
 
 void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{   char *p;
+{   const char *p;
 
     switch (protection)
     {
@@ -721,7 +721,7 @@
 
 const char *AnonDeclaration::kind()
 {
-    return (char *)(isunion ? "anonymous union" : "anonymous struct");
+    return (isunion ? "anonymous union" : "anonymous struct");
 }
 
 /********************************* PragmaDeclaration ****************************/
@@ -1363,6 +1363,7 @@
 CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
     : AttribDeclaration(NULL)
 {
+    //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
     this->loc = loc;
     this->exp = exp;
     this->sd = NULL;
@@ -1392,7 +1393,7 @@
 
 void CompileDeclaration::compileIt(Scope *sc)
 {
-    //printf("CompileDeclaration::compileIt()\n");
+    //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum);
     exp = exp->semantic(sc);
     exp = resolveProperties(sc, exp);
     exp = exp->optimize(WANTvalue | WANTinterpret);
--- a/dmd/class.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/class.c	Tue Jan 06 16:33:51 2009 +0100
@@ -539,7 +539,16 @@
     sc->inunion = 0;
 
     if (isCOMclass())
+    {
+#if _WIN32
 	sc->linkage = LINKwindows;
+#else
+	/* This enables us to use COM objects under Linux and
+	 * work with things like XPCOM
+	 */
+	sc->linkage = LINKc;
+#endif
+    }
     sc->protection = PROTpublic;
     sc->explicitProtection = 0;
     sc->structalign = 8;
--- a/dmd/cond.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/cond.c	Tue Jan 06 16:33:51 2009 +0100
@@ -1,391 +1,391 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "id.h"
-#include "init.h"
-#include "declaration.h"
-#include "identifier.h"
-#include "expression.h"
-#include "cond.h"
-#include "module.h"
-#include "template.h"
-#include "lexer.h"
-#ifdef _DH
-#include "mtype.h"
-#include "scope.h"
-#endif
-
-int findCondition(Array *ids, Identifier *ident)
-{
-    if (ids)
-    {
-	for (int i = 0; i < ids->dim; i++)
-	{
-	    char *id = (char *)ids->data[i];
-
-	    if (strcmp(id, ident->toChars()) == 0)
-		return TRUE;
-	}
-    }
-
-    return FALSE;
-}
-
-/* ============================================================ */
-
-Condition::Condition(Loc loc)
-{
-    this->loc = loc;
-    inc = 0;
-}
-
-/* ============================================================ */
-
-DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
-	: Condition(0)
-{
-    this->mod = mod;
-    this->level = level;
-    this->ident = ident;
-}
-
-Condition *DVCondition::syntaxCopy()
-{
-    return this;	// don't need to copy
-}
-
-/* ============================================================ */
-
-void DebugCondition::setGlobalLevel(unsigned level)
-{
-    global.params.debuglevel = level;
-}
-
-void DebugCondition::addGlobalIdent(char *ident)
-{
-    if (!global.params.debugids)
-	global.params.debugids = new Array();
-    global.params.debugids->push(ident);
-}
-
-
-DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
-    : DVCondition(mod, level, ident)
-{
-}
-
-int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
-{
-    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
-    if (inc == 0)
-    {
-	inc = 2;
-	if (ident)
-	{
-	    if (findCondition(mod->debugids, ident))
-		inc = 1;
-	    else if (findCondition(global.params.debugids, ident))
-		inc = 1;
-	    else
-	    {	if (!mod->debugidsNot)
-		    mod->debugidsNot = new Array();
-		mod->debugidsNot->push(ident->toChars());
-	    }
-	}
-	else if (level <= global.params.debuglevel || level <= mod->debuglevel)
-	    inc = 1;
-    }
-    return (inc == 1);
-}
-
-void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    if (ident)
-	buf->printf("debug (%s)", ident->toChars());
-    else
-	buf->printf("debug (%u)", level);
-}
-
-/* ============================================================ */
-
-void VersionCondition::setGlobalLevel(unsigned level)
-{
-    global.params.versionlevel = level;
-}
-
-void VersionCondition::checkPredefined(Loc loc, char *ident)
-{
-    static char* reserved[] =
-    {
-	"DigitalMars", "LLVM", "LDC", "LLVM64",
-    "X86", "X86_64", "PPC", "PPC64",
-	"Windows", "Win32", "Win64",
-	"linux", "darwin", "Posix",
-	"LittleEndian", "BigEndian",
-	"all",
-	"none",
-    };
-
-    for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
-    {
-	if (strcmp(ident, reserved[i]) == 0)
-	    goto Lerror;
-    }
-
-    if (ident[0] == 'D' && ident[1] == '_')
-	goto Lerror;
-
-    return;
-
-  Lerror:
-    error(loc, "version identifier '%s' is reserved and cannot be set", ident);
-}
-
-void VersionCondition::addGlobalIdent(char *ident)
-{
-    checkPredefined(0, ident);
-    addPredefinedGlobalIdent(ident);
-}
-
-void VersionCondition::addPredefinedGlobalIdent(char *ident)
-{
-    if (!global.params.versionids)
-	global.params.versionids = new Array();
-    global.params.versionids->push(ident);
-}
-
-
-VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
-    : DVCondition(mod, level, ident)
-{
-}
-
-int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
-{
-    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
-    //if (ident) printf("\tident = '%s'\n", ident->toChars());
-    if (inc == 0)
-    {
-	inc = 2;
-	if (ident)
-	{
-	    if (findCondition(mod->versionids, ident))
-		inc = 1;
-	    else if (findCondition(global.params.versionids, ident))
-		inc = 1;
-	    else
-	    {
-		if (!mod->versionidsNot)
-		    mod->versionidsNot = new Array();
-		mod->versionidsNot->push(ident->toChars());
-	    }
-	}
-	else if (level <= global.params.versionlevel || level <= mod->versionlevel)
-	    inc = 1;
-    }
-    return (inc == 1);
-}
-
-void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    if (ident)
-	buf->printf("version (%s)", ident->toChars());
-    else
-	buf->printf("version (%u)", level);
-}
-
-
-/**************************** StaticIfCondition *******************************/
-
-StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
-    : Condition(loc)
-{
-    this->exp = exp;
-}
-
-Condition *StaticIfCondition::syntaxCopy()
-{
-    return new StaticIfCondition(loc, exp->syntaxCopy());
-}
-
-int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
-{
-#if 0
-    printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
-    if (s)
-    {
-	printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
-    }
-#endif
-    if (inc == 0)
-    {
-	if (!sc)
-	{
-	    error(loc, "static if conditional cannot be at global scope");
-	    inc = 2;
-	    return 0;
-	}
-
-	sc = sc->push(sc->scopesym);
-	sc->sd = s;			// s gets any addMember()
-	sc->flags |= SCOPEstaticif;
-	Expression *e = exp->semantic(sc);
-	sc->pop();
-	e = e->optimize(WANTvalue | WANTinterpret);
-	if (e->isBool(TRUE))
-	    inc = 1;
-	else if (e->isBool(FALSE))
-	    inc = 2;
-	else
-	{
-	    e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
-	    inc = 2;
-	}
-    }
-    return (inc == 1);
-}
-
-void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("static if(");
-    exp->toCBuffer(buf, hgs);
-    buf->writeByte(')');
-}
-
-
-/**************************** IftypeCondition *******************************/
-
-IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
-    : Condition(loc)
-{
-    this->targ = targ;
-    this->id = id;
-    this->tok = tok;
-    this->tspec = tspec;
-}
-
-Condition *IftypeCondition::syntaxCopy()
-{
-    return new IftypeCondition(loc,
-	targ->syntaxCopy(),
-	id,
-	tok,
-	tspec ? tspec->syntaxCopy() : NULL);
-}
-
-int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
-{
-    //printf("IftypeCondition::include()\n");
-    if (inc == 0)
-    {
-	if (!sc)
-	{
-	    error(loc, "iftype conditional cannot be at global scope");
-	    inc = 2;
-	    return 0;
-	}
-	unsigned errors = global.errors;
-	global.gag++;			// suppress printing of error messages
-	targ = targ->semantic(loc, sc);
-	global.gag--;
-	if (errors != global.errors)	// if any errors happened
-	{   inc = 2;			// then condition is false
-	    global.errors = errors;
-	}
-	else if (id && tspec)
-	{
-	    /* Evaluate to TRUE if targ matches tspec.
-	     * If TRUE, declare id as an alias for the specialized type.
-	     */
-
-	    MATCH m;
-	    TemplateTypeParameter tp(loc, id, NULL, NULL);
-
-	    TemplateParameters parameters;
-	    parameters.setDim(1);
-	    parameters.data[0] = (void *)&tp;
-
-	    Objects dedtypes;
-	    dedtypes.setDim(1);
-
-	    m = targ->deduceType(NULL, tspec, &parameters, &dedtypes);
-	    if (m == MATCHnomatch ||
-		(m != MATCHexact && tok == TOKequal))
-		inc = 2;
-	    else
-	    {
-		inc = 1;
-		Type *tded = (Type *)dedtypes.data[0];
-		if (!tded)
-		    tded = targ;
-		Dsymbol *s = new AliasDeclaration(loc, id, tded);
-		s->semantic(sc);
-		sc->insert(s);
-		if (sd)
-		    s->addMember(sc, sd, 1);
-	    }
-	}
-	else if (id)
-	{
-	    /* Declare id as an alias for type targ. Evaluate to TRUE
-	     */
-	    Dsymbol *s = new AliasDeclaration(loc, id, targ);
-	    s->semantic(sc);
-	    sc->insert(s);
-	    if (sd)
-		s->addMember(sc, sd, 1);
-	    inc = 1;
-	}
-	else if (tspec)
-	{
-	    /* Evaluate to TRUE if targ matches tspec
-	     */
-	    tspec = tspec->semantic(loc, sc);
-	    //printf("targ  = %s\n", targ->toChars());
-	    //printf("tspec = %s\n", tspec->toChars());
-	    if (tok == TOKcolon)
-	    {   if (targ->implicitConvTo(tspec))
-		    inc = 1;
-		else
-		    inc = 2;
-	    }
-	    else /* == */
-	    {	if (targ->equals(tspec))
-		    inc = 1;
-		else
-		    inc = 2;
-	    }
-	}
-	else
-	     inc = 1;
-	//printf("inc = %d\n", inc);
-    }
-    return (inc == 1);
-}
-
-void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
-{
-    buf->writestring("iftype(");
-    targ->toCBuffer(buf, id, hgs);
-    if (tspec)
-    {
-	if (tok == TOKcolon)
-	    buf->writestring(" : ");
-	else
-	    buf->writestring(" == ");
-	tspec->toCBuffer(buf, NULL, hgs);
-    }
-    buf->writeByte(')');
-}
-
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "identifier.h"
+#include "expression.h"
+#include "cond.h"
+#include "module.h"
+#include "template.h"
+#include "lexer.h"
+#ifdef _DH
+#include "mtype.h"
+#include "scope.h"
+#endif
+
+int findCondition(Array *ids, Identifier *ident)
+{
+    if (ids)
+    {
+	for (int i = 0; i < ids->dim; i++)
+	{
+	    char *id = (char *)ids->data[i];
+
+	    if (strcmp(id, ident->toChars()) == 0)
+		return TRUE;
+	}
+    }
+
+    return FALSE;
+}
+
+/* ============================================================ */
+
+Condition::Condition(Loc loc)
+{
+    this->loc = loc;
+    inc = 0;
+}
+
+/* ============================================================ */
+
+DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
+	: Condition(0)
+{
+    this->mod = mod;
+    this->level = level;
+    this->ident = ident;
+}
+
+Condition *DVCondition::syntaxCopy()
+{
+    return this;	// don't need to copy
+}
+
+/* ============================================================ */
+
+void DebugCondition::setGlobalLevel(unsigned level)
+{
+    global.params.debuglevel = level;
+}
+
+void DebugCondition::addGlobalIdent(char *ident)
+{
+    if (!global.params.debugids)
+	global.params.debugids = new Array();
+    global.params.debugids->push(ident);
+}
+
+
+DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->debugids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.debugids, ident))
+		inc = 1;
+	    else
+	    {	if (!mod->debugidsNot)
+		    mod->debugidsNot = new Array();
+		mod->debugidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.debuglevel || level <= mod->debuglevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("debug (%s)", ident->toChars());
+    else
+	buf->printf("debug (%u)", level);
+}
+
+/* ============================================================ */
+
+void VersionCondition::setGlobalLevel(unsigned level)
+{
+    global.params.versionlevel = level;
+}
+
+void VersionCondition::checkPredefined(Loc loc, char *ident)
+{
+    static const char* reserved[] =
+    {
+	"DigitalMars", "LLVM", "LDC", "LLVM64",
+    "X86", "X86_64", "PPC", "PPC64",
+	"Windows", "Win32", "Win64",
+	"linux", "darwin", "Posix",
+	"LittleEndian", "BigEndian",
+	"all",
+	"none",
+    };
+
+    for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
+    {
+	if (strcmp(ident, reserved[i]) == 0)
+	    goto Lerror;
+    }
+
+    if (ident[0] == 'D' && ident[1] == '_')
+	goto Lerror;
+
+    return;
+
+  Lerror:
+    error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+}
+
+void VersionCondition::addGlobalIdent(char *ident)
+{
+    checkPredefined(0, ident);
+    addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(char *ident)
+{
+    if (!global.params.versionids)
+	global.params.versionids = new Array();
+    global.params.versionids->push(ident);
+}
+
+
+VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
+    //if (ident) printf("\tident = '%s'\n", ident->toChars());
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->versionids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.versionids, ident))
+		inc = 1;
+	    else
+	    {
+		if (!mod->versionidsNot)
+		    mod->versionidsNot = new Array();
+		mod->versionidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.versionlevel || level <= mod->versionlevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("version (%s)", ident->toChars());
+    else
+	buf->printf("version (%u)", level);
+}
+
+
+/**************************** StaticIfCondition *******************************/
+
+StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
+    : Condition(loc)
+{
+    this->exp = exp;
+}
+
+Condition *StaticIfCondition::syntaxCopy()
+{
+    return new StaticIfCondition(loc, exp->syntaxCopy());
+}
+
+int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+#if 0
+    printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
+    if (s)
+    {
+	printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
+    }
+#endif
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "static if conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+
+	sc = sc->push(sc->scopesym);
+	sc->sd = s;			// s gets any addMember()
+	sc->flags |= SCOPEstaticif;
+	Expression *e = exp->semantic(sc);
+	sc->pop();
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->isBool(TRUE))
+	    inc = 1;
+	else if (e->isBool(FALSE))
+	    inc = 2;
+	else
+	{
+	    e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
+	    inc = 2;
+	}
+    }
+    return (inc == 1);
+}
+
+void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("static if(");
+    exp->toCBuffer(buf, hgs);
+    buf->writeByte(')');
+}
+
+
+/**************************** IftypeCondition *******************************/
+
+IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
+    : Condition(loc)
+{
+    this->targ = targ;
+    this->id = id;
+    this->tok = tok;
+    this->tspec = tspec;
+}
+
+Condition *IftypeCondition::syntaxCopy()
+{
+    return new IftypeCondition(loc,
+	targ->syntaxCopy(),
+	id,
+	tok,
+	tspec ? tspec->syntaxCopy() : NULL);
+}
+
+int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("IftypeCondition::include()\n");
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "iftype conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+	unsigned errors = global.errors;
+	global.gag++;			// suppress printing of error messages
+	targ = targ->semantic(loc, sc);
+	global.gag--;
+	if (errors != global.errors)	// if any errors happened
+	{   inc = 2;			// then condition is false
+	    global.errors = errors;
+	}
+	else if (id && tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec.
+	     * If TRUE, declare id as an alias for the specialized type.
+	     */
+
+	    MATCH m;
+	    TemplateTypeParameter tp(loc, id, NULL, NULL);
+
+	    TemplateParameters parameters;
+	    parameters.setDim(1);
+	    parameters.data[0] = (void *)&tp;
+
+	    Objects dedtypes;
+	    dedtypes.setDim(1);
+
+	    m = targ->deduceType(NULL, tspec, &parameters, &dedtypes);
+	    if (m == MATCHnomatch ||
+		(m != MATCHexact && tok == TOKequal))
+		inc = 2;
+	    else
+	    {
+		inc = 1;
+		Type *tded = (Type *)dedtypes.data[0];
+		if (!tded)
+		    tded = targ;
+		Dsymbol *s = new AliasDeclaration(loc, id, tded);
+		s->semantic(sc);
+		sc->insert(s);
+		if (sd)
+		    s->addMember(sc, sd, 1);
+	    }
+	}
+	else if (id)
+	{
+	    /* Declare id as an alias for type targ. Evaluate to TRUE
+	     */
+	    Dsymbol *s = new AliasDeclaration(loc, id, targ);
+	    s->semantic(sc);
+	    sc->insert(s);
+	    if (sd)
+		s->addMember(sc, sd, 1);
+	    inc = 1;
+	}
+	else if (tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec
+	     */
+	    tspec = tspec->semantic(loc, sc);
+	    //printf("targ  = %s\n", targ->toChars());
+	    //printf("tspec = %s\n", tspec->toChars());
+	    if (tok == TOKcolon)
+	    {   if (targ->implicitConvTo(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	    else /* == */
+	    {	if (targ->equals(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	}
+	else
+	     inc = 1;
+	//printf("inc = %d\n", inc);
+    }
+    return (inc == 1);
+}
+
+void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("iftype(");
+    targ->toCBuffer(buf, id, hgs);
+    if (tspec)
+    {
+	if (tok == TOKcolon)
+	    buf->writestring(" : ");
+	else
+	    buf->writestring(" == ");
+	tspec->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writeByte(')');
+}
+
+
--- a/dmd/doc.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/doc.c	Tue Jan 06 16:33:51 2009 +0100
@@ -47,9 +47,9 @@
 
 struct Escape
 {
-    char *strings[256];
+    const char *strings[256];
 
-    static char *escapeChar(unsigned c);
+    static const char *escapeChar(unsigned c);
 };
 
 struct Section
@@ -96,8 +96,8 @@
 };
 
 
-int cmp(char *stringz, void *s, size_t slen);
-int icmp(char *stringz, void *s, size_t slen);
+int cmp(const char *stringz, void *s, size_t slen);
+int icmp(const char *stringz, void *s, size_t slen);
 int isDitto(unsigned char *comment);
 unsigned char *skipwhitespace(unsigned char *p);
 unsigned skiptoident(OutBuffer *buf, unsigned i);
@@ -404,7 +404,7 @@
     OutBuffer *buf = sc->docbuf;
 
     if (members)
-    {	char *m = "$(DDOC_MEMBERS \n";
+    {	const char *m = "$(DDOC_MEMBERS \n";
 
 	if (isModule())
 	    m = "$(DDOC_MODULE_MEMBERS \n";
@@ -441,7 +441,7 @@
 
 void emitProtection(OutBuffer *buf, PROT prot)
 {
-    char *p;
+    const char *p;
 
     switch (prot)
     {
@@ -918,6 +918,7 @@
 DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment)
 {   unsigned idlen;
 
+    //printf("parse(%s): '%s'\n", s->toChars(), comment);
     if (sc->lastdc && isDitto(comment))
 	return NULL;
 
@@ -963,6 +964,7 @@
     unsigned char *name = NULL;
     unsigned namelen = 0;
 
+    //printf("parseSections('%s')\n", comment);
     p = comment;
     while (*p)
     {
@@ -1088,7 +1090,7 @@
 {
     if (namelen)
     {
-	static char *table[] =
+	static const char *table[] =
 	{	"AUTHORS", "BUGS", "COPYRIGHT", "DATE",
 		"DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE",
 		"RETURNS", "SEE_ALSO", "STANDARDS", "THROWS",
@@ -1432,7 +1434,7 @@
  * Return < 0, ==0, > 0
  */
 
-int cmp(char *stringz, void *s, size_t slen)
+int cmp(const char *stringz, void *s, size_t slen)
 {
     size_t len1 = strlen(stringz);
 
@@ -1441,7 +1443,7 @@
     return memcmp(stringz, s, slen);
 }
 
-int icmp(char *stringz, void *s, size_t slen)
+int icmp(const char *stringz, void *s, size_t slen)
 {
     size_t len1 = strlen(stringz);
 
@@ -1578,7 +1580,7 @@
 
 int isKeyword(unsigned char *p, unsigned len)
 {
-    static char *table[] = { "true", "false", "null" };
+    static const char *table[] = { "true", "false", "null" };
 
     for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
     {
@@ -1629,10 +1631,10 @@
 void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
 {
     //printf("highlightText()\n");
-    char *sid = s->ident->toChars();
+    const char *sid = s->ident->toChars();
     FuncDeclaration *f = s->isFuncDeclaration();
     unsigned char *p;
-    char *se;
+    const char *se;
 
     int leadingBlank = 1;
     int inCode = 0;
@@ -1878,7 +1880,7 @@
     //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind());
     for (unsigned i = offset; i < buf->offset; i++)
     {	unsigned char c = buf->data[i];
-	char *se;
+	const char *se;
 
 	se = Escape::escapeChar(c);
 	if (se)
@@ -1920,7 +1922,7 @@
 void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend)
 {
     for (; p < pend; p++)
-    {	char *s = Escape::escapeChar(*p);
+    {	const char *s = Escape::escapeChar(*p);
 	if (s)
 	    buf->writestring(s);
 	else
@@ -1942,7 +1944,7 @@
     Token tok;
     OutBuffer res;
     unsigned char *lastp = buf->data;
-    char *highlight;
+    const char *highlight;
 
     //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data);
     res.reserve(buf->offset);
@@ -2003,8 +2005,8 @@
  * Find character string to replace c with.
  */
 
-char *Escape::escapeChar(unsigned c)
-{   char *s;
+const char *Escape::escapeChar(unsigned c)
+{   const char *s;
 
     switch (c)
     {
--- a/dmd/expression.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/expression.c	Tue Jan 06 16:33:51 2009 +0100
@@ -12,7 +12,10 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <assert.h>
+#if _MSC_VER
 #include <complex>
+#else
+#endif
 #include <math.h>
 
 #if _WIN32 && __DMC__
@@ -68,6 +71,7 @@
 #include "parse.h"
 
 Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim);
+Expression *expandVar(int result, VarDeclaration *v);
 
 #define LOGSEMANTIC	0
 
@@ -168,10 +172,20 @@
     precedence[TOKue] = PREC_rel;
     precedence[TOKin] = PREC_rel;
 
+#if 0
     precedence[TOKequal] = PREC_equal;
     precedence[TOKnotequal] = PREC_equal;
     precedence[TOKidentity] = PREC_equal;
     precedence[TOKnotidentity] = PREC_equal;
+#else
+    /* Note that we changed precedence, so that < and != have the same
+     * precedence. This change is in the parser, too.
+     */
+    precedence[TOKequal] = PREC_rel;
+    precedence[TOKnotequal] = PREC_rel;
+    precedence[TOKidentity] = PREC_rel;
+    precedence[TOKnotidentity] = PREC_rel;
+#endif
 
     precedence[TOKand] = PREC_and;
 
@@ -352,7 +366,7 @@
     {
 	Type *t = e->type->toBasetype();
 
-	if (t->ty == Tfunction)
+	if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/)
 	{
 	    e = new CallExp(e->loc, e);
 	    e = e->semantic(sc);
@@ -539,8 +553,6 @@
 void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments)
 {
     unsigned n;
-    int done;
-    Type *tb;
 
     //printf("functionArguments()\n");
     assert(arguments);
@@ -552,7 +564,7 @@
 
     n = (nargs > nparams) ? nargs : nparams;	// n = max(nargs, nparams)
 
-    done = 0;
+    int done = 0;
     for (size_t i = 0; i < n; i++)
     {
 	Expression *arg;
@@ -561,6 +573,7 @@
 	    arg = (Expression *)arguments->data[i];
 	else
 	    arg = NULL;
+	Type *tb;
 
 	if (i < nparams)
 	{
@@ -615,11 +628,8 @@
 			    break;
 			}
 #endif
-			static int idn;
-			char name[10 + sizeof(idn)*3 + 1];
-			sprintf(name, "__arrayArg%d", ++idn);
-			Identifier *id = Lexer::idPool(name);
-			Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i));
+			Identifier *id = Lexer::uniqueId("__arrayArg");
+			Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i));
 			t = t->semantic(loc, sc);
 			VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc));
 			v->semantic(sc);
@@ -631,16 +641,19 @@
 
 			for (size_t u = i; u < nargs; u++)
 			{   Expression *a = (Expression *)arguments->data[u];
-			    if (tret && !tb->next->equals(a->type))
+			    if (tret && !((TypeArray *)tb)->next->equals(a->type))
 				a = a->toDelegate(sc, tret);
 
 			    Expression *e = new VarExp(loc, v);
 			    e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams));
-			    e = new AssignExp(loc, e, a);
+			    AssignExp *ae = new AssignExp(loc, e, a);
+#if DMDV2
+			    ae->op = TOKconstruct;
+#endif
 			    if (c)
-				c = new CommaExp(loc, c, e);
+				c = new CommaExp(loc, c, ae);
 			    else
-				c = e;
+				c = ae;
 			}
 			arg = new VarExp(loc, v);
 			if (c)
@@ -694,12 +707,50 @@
 	    }
 #endif
 
+#if DMDV2
+	    if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout)))
+	    {
+		arg = callCpCtor(loc, sc, arg);
+	    }
+#endif
+
 
 	    // Convert lazy argument to a delegate
 	    if (p->storageClass & STClazy)
 	    {
 		arg = arg->toDelegate(sc, p->type);
 	    }
+#if DMDV2
+	    /* Look for arguments that cannot 'escape' from the called
+	     * function.
+	     */
+	    if (!tf->parameterEscapes(p))
+	    {
+		/* Function literals can only appear once, so if this
+		 * appearance was scoped, there cannot be any others.
+		 */
+		if (arg->op == TOKfunction)
+		{   FuncExp *fe = (FuncExp *)arg;
+		    fe->fd->tookAddressOf = 0;
+		}
+
+		/* For passing a delegate to a scoped parameter,
+		 * this doesn't count as taking the address of it.
+		 * We only worry about 'escaping' references to the function.
+		 */
+		else if (arg->op == TOKdelegate)
+		{   DelegateExp *de = (DelegateExp *)arg;
+		    if (de->e1->op == TOKvar)
+		    {	VarExp *ve = (VarExp *)de->e1;
+			FuncDeclaration *f = ve->var->isFuncDeclaration();
+			if (f)
+			{   f->tookAddressOf--;
+			    //printf("tookAddressOf = %d\n", f->tookAddressOf);
+			}
+		    }
+		}
+	    }
+#endif
 	}
 	else
 	{
@@ -778,7 +829,11 @@
 void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr)
 {
     //if (precedence[e->op] == 0) e->dump(0);
-    if (precedence[e->op] < pr)
+    if (precedence[e->op] < pr ||
+	/* Despite precedence, we don't allow a<b<c expressions.
+	 * They must be parenthesized.
+	 */
+	(pr == PREC_rel && precedence[e->op] == pr))
     {
 	buf->writeByte('(');
 	e->toCBuffer(buf, hgs);
@@ -982,6 +1037,16 @@
     error("expression %s is not a valid template value argument", toChars());
 }
 
+/***************************************
+ * Return !=0 if expression is an lvalue.
+ */
+#if DMDV2
+int Expression::isLvalue()
+{
+    return 0;
+}
+#endif
+
 /*******************************
  * Give error if we're not an lvalue.
  * If we can, convert expression to be an lvalue.
@@ -1002,6 +1067,10 @@
     //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
 
     // See if this expression is a modifiable lvalue (i.e. not const)
+#if DMDV2
+    if (type && (!type->isMutable() || !type->isAssignable()))
+	error("%s is not mutable", e->toChars());
+#endif
     return toLvalue(sc, e);
 }
 
@@ -1049,6 +1118,15 @@
     s->checkDeprecated(loc, sc);
 }
 
+#if DMDV2
+void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
+{
+    if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure())
+	error("pure function '%s' cannot call impure function '%s'\n",
+	    sc->func->toChars(), f->toChars());
+}
+#endif
+
 /********************************
  * Check for expressions that have no use.
  * Input:
@@ -1175,7 +1253,11 @@
 
 int Expression::canThrow()
 {
+#if DMDV2
+    return FALSE;
+#else
     return TRUE;
+#endif
 }
 
 
@@ -1849,7 +1931,9 @@
 		// ArrayScopeSymbol::search() doesn't have access to sc.
 		s->semantic(sc);
 	    }
-	    // Look to see if f is really a function template
+	    /* If f is really a function template,
+	     * then replace f with the function template declaration.
+	     */
 	    FuncDeclaration *f = s->isFuncDeclaration();
 	    if (f && f->parent)
 	    {   TemplateInstance *ti = f->parent->isTemplateInstance();
@@ -1891,6 +1975,13 @@
 	buf->writestring(ident->toChars());
 }
 
+#if DMDV2
+int IdentifierExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e)
 {
 #if 0
@@ -1954,7 +2045,11 @@
     // BUG: This should happen after overload resolution for functions, not before
     if (s->needThis())
     {
-	if (hasThis(sc) /*&& !s->isFuncDeclaration()*/)
+	if (hasThis(sc)
+#if DMDV2
+		&& !s->isFuncDeclaration()
+#endif
+	    )
 	{
 	    // Supply an implicit 'this', as in
 	    //	  this.ident
@@ -2112,6 +2207,13 @@
     buf->writestring(s->toChars());
 }
 
+#if DMDV2
+int DsymbolExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e)
 {
 #if 0
@@ -2214,6 +2316,13 @@
     buf->writestring("this");
 }
 
+#if DMDV2
+int ThisExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
 {
     return this;
@@ -2431,7 +2540,7 @@
     if (!type)
     {	OutBuffer buffer;
 	size_t newlen = 0;
-	char *p;
+	const char *p;
 	size_t u;
 	unsigned c;
 
@@ -2629,7 +2738,7 @@
 void StringExp::toMangleBuffer(OutBuffer *buf)
 {   char m;
     OutBuffer tmp;
-    char *p;
+    const char *p;
     unsigned c;
     size_t u;
     unsigned char *q;
@@ -2772,6 +2881,13 @@
     return result ? (dim != 0) : (dim == 0);
 }
 
+#if DMDV2
+int ArrayLiteralExp::canThrow()
+{
+    return 1;	// because it can fail allocating memory
+}
+#endif
+
 void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writeByte('[');
@@ -2890,6 +3006,13 @@
     return result ? (dim != 0) : (dim == 0);
 }
 
+#if DMDV2
+int AssocArrayLiteralExp::canThrow()
+{
+    return 1;
+}
+#endif
+
 void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writeByte('[');
@@ -3074,6 +3197,12 @@
     return -1;
 }
 
+#if DMDV2
+int StructLiteralExp::isLvalue()
+{
+    return 1;
+}
+#endif
 
 Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e)
 {
@@ -3096,6 +3225,13 @@
     return f;
 }
 
+#if DMDV2
+int StructLiteralExp::canThrow()
+{
+    return arrayExpressionCanThrow(elements);
+}
+#endif
+
 void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring(sd->toChars());
@@ -3287,6 +3423,8 @@
 
 /********************** NewExp **************************************/
 
+/* thisexp.new(newargs) newtype(arguments) */
+
 NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
 	Type *newtype, Expressions *arguments)
     : Expression(loc, TOKnew, sizeof(NewExp))
@@ -3472,17 +3610,14 @@
 	}
 
 	if (cd->aggNew)
-	{   Expression *e;
-
-	    f = cd->aggNew;
-
+	{
 	    // Prepend the uint size argument to newargs[]
-	    e = new IntegerExp(loc, cd->size(loc), Type::tuns32);
+	    Expression *e = new IntegerExp(loc, cd->size(loc), Type::tuns32);
 	    if (!newargs)
 		newargs = new Expressions();
 	    newargs->shift(e);
 
-	    f = f->overloadResolve(loc, newargs);
+	    f = cd->aggNew->overloadResolve(loc, newargs);
 	    allocator = f->isNewDeclaration();
 	    assert(allocator);
 
@@ -3494,7 +3629,6 @@
 	    if (newargs && newargs->dim)
 		error("no allocator for %s", cd->toChars());
 	}
-
     }
     else if (tb->ty == Tstruct)
     {
@@ -3575,6 +3709,13 @@
     return 1;
 }
 
+#if DMDV2
+int NewExp::canThrow()
+{
+    return 1;
+}
+#endif
+
 void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {   int i;
 
@@ -3642,6 +3783,13 @@
     return 1;
 }
 
+#if DMDV2
+int NewAnonClassExp::canThrow()
+{
+    return 1;
+}
+#endif
+
 void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {   int i;
 
@@ -3670,6 +3818,18 @@
     }
 }
 
+/********************** SymbolExp **************************************/
+
+#if DMDV2
+SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads)
+    : Expression(loc, op, size)
+{
+    assert(var);
+    this->var = var;
+    this->hasOverloads = hasOverloads;
+}
+#endif
+
 /********************** SymOffExp **************************************/
 
 SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset)
@@ -3760,6 +3920,11 @@
 	}
 #endif
     }
+    /* Fix for 1161 doesn't work because it causes protection
+     * problems when instantiating imported templates passing private
+     * variables as alias template parameters.
+     */
+    //accessCheck(loc, sc, NULL, var);
 
     VarDeclaration *v = var->isVarDeclaration();
     if (v)
@@ -3774,6 +3939,13 @@
 	    }
 	}
 	v->checkNestedReference(sc, loc);
+#if DMDV2
+	if (sc->func && sc->func->isPure() && !sc->intypeof)
+	{
+	    if (v->isDataseg() && !v->isInvariant())
+		error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars());
+	}
+#endif
     }
 #if 0
     else if ((fd = var->isFuncLiteralDeclaration()) != NULL)
@@ -3812,6 +3984,15 @@
     }
 }
 
+#if DMDV2
+int VarExp::isLvalue()
+{
+    if (var->storage_class & STClazy)
+	return 0;
+    return 1;
+}
+#endif
+
 Expression *VarExp::toLvalue(Scope *sc, Expression *e)
 {
 #if 0
@@ -4026,6 +4207,13 @@
     return f;
 }
 
+#if DMDV2
+int TupleExp::canThrow()
+{
+    return arrayExpressionCanThrow(exps);
+}
+#endif
+
 void TupleExp::checkEscape()
 {
     for (size_t i = 0; i < exps->dim; i++)
@@ -4195,6 +4383,18 @@
     return 1;
 }
 
+#if DMDV2
+int DeclarationExp::canThrow()
+{
+    VarDeclaration *v = declaration->isVarDeclaration();
+    if (v && v->init)
+    {	ExpInitializer *ie = v->init->isExpInitializer();
+	return ie && ie->exp->canThrow();
+    }
+    return 0;
+}
+#endif
+
 void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     declaration->toCBuffer(buf, hgs);
@@ -4398,6 +4598,7 @@
 		break;
 
 	    case TOKinvariant:
+	    case TOKimmutable:
 		if (!targ->isInvariant())
 		    goto Lno;
 		tded = targ;
@@ -4604,6 +4805,13 @@
     return this;
 }
 
+#if DMDV2
+int UnaExp::canThrow()
+{
+    return e1->canThrow();
+}
+#endif
+
 void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring(Token::toChars(op));
@@ -4773,6 +4981,13 @@
     return e1->type->isunsigned() || e2->type->isunsigned();
 }
 
+#if DMDV2
+int BinExp::canThrow()
+{
+    return e1->canThrow() || e2->canThrow();
+}
+#endif
+
 void BinExp::incompatibleTypes()
 {
     error("incompatible types for ((%s) %s (%s)): '%s' and '%s'",
@@ -4805,6 +5020,7 @@
     Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
     p.loc = loc;
     p.nextToken();
+    //printf("p.loc.linnum = %d\n", p.loc.linnum);
     Expression *e = p.parseExpression();
     if (p.token.value != TOKeof)
 	error("incomplete mixin expression (%s)", se->toChars());
@@ -4877,7 +5093,7 @@
     return se->semantic(sc);
 
   Lerror:
-    se = new StringExp(loc, "");
+    se = new StringExp(loc, (char *)"");
     goto Lret;
 }
 
@@ -4940,6 +5156,13 @@
     return 1;
 }
 
+#if DMDV2
+int AssertExp::canThrow()
+{
+    return (global.params.useAssert != 0);
+}
+#endif
+
 void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("assert(");
@@ -5162,6 +5385,13 @@
 		}
 		return e;
 	    }
+#if DMDV2
+	    OverloadSet *o = s->isOverloadSet();
+	    if (o)
+	    {   //printf("'%s' is an overload set\n", o->toChars());
+		return new OverExp(o);
+	    }
+#endif
 
 	    Type *t = s->getType();
 	    if (t)
@@ -5224,6 +5454,29 @@
 	e->type = ((TypePointer *)e1->type)->next;
 	return e->type->dotExp(sc, e, ident);
     }
+#if DMDV2
+    else if (t1b->ty == Tarray ||
+             t1b->ty == Tsarray ||
+	     t1b->ty == Taarray)
+    {	/* If ident is not a valid property, rewrite:
+	 *   e1.ident
+         * as:
+         *   .ident(e1)
+         */
+	unsigned errors = global.errors;
+	global.gag++;
+	e = e1->type->dotExp(sc, e1, ident);
+	global.gag--;
+	if (errors != global.errors)	// if failed to find the property
+	{
+	    global.errors = errors;
+	    e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident);
+	    e = new CallExp(loc, e, e1);
+	}
+	e = e->semantic(sc);
+	return e;
+    }
+#endif
     else
     {
 	e = e1->type->dotExp(sc, e1, ident);
@@ -5341,6 +5594,13 @@
     return this;
 }
 
+#if DMDV2
+int DotVarExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *DotVarExp::toLvalue(Scope *sc, Expression *e)
 {
     //printf("DotVarExp::toLvalue(%s)\n", toChars());
@@ -5391,6 +5651,20 @@
 	    break;
 	}
     }
+#if DMDV2
+    else
+    {
+	Type *t1 = e1->type->toBasetype();
+
+	if (!t1->isMutable() ||
+	    (t1->ty == Tpointer && !t1->nextOf()->isMutable()) ||
+	    !var->type->isMutable() ||
+	    !var->type->isAssignable() ||
+	    var->storage_class & STCmanifest
+	   )
+	    error("cannot modify const/invariant %s", toChars());
+    }
+#endif
     return this;
 }
 
@@ -5713,12 +5987,16 @@
 		if (!arguments)
 		    arguments = new Expressions();
 		arguments->shift(dotid->e1);
+#if DMDV2
+		e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident);
+#else
 		e1 = new IdentifierExp(dotid->loc, dotid->ident);
-	    }
-	}
-    }
-
-#if DMDV2
+#endif
+	    }
+	}
+    }
+
+#if 1
     /* This recognizes:
      *	foo!(tiargs)(funcargs)
      */
@@ -5901,7 +6179,7 @@
 	    if (!arguments)
 		// Should fix deduceFunctionTemplate() so it works on NULL argument
 		arguments = new Expressions();
-	    f = td->deduceFunctionTemplate(sc, loc, NULL, arguments);
+	    f = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments);
 	    if (!f)
 	    {	type = Type::terror;
 		return this;
@@ -5925,6 +6203,9 @@
 	}
 
 	checkDeprecated(sc, f);
+#if DMDV2
+	checkPurity(sc, f);
+#endif
 	accessCheck(loc, sc, ue->e1, f);
 	if (!f->needThis())
 	{
@@ -5990,6 +6271,9 @@
 
 		f = f->overloadResolve(loc, arguments);
 		checkDeprecated(sc, f);
+#if DMDV2
+		checkPurity(sc, f);
+#endif
 		e1 = new DotVarExp(e1->loc, e1, f);
 		e1 = e1->semantic(sc);
 		t1 = e1->type;
@@ -6027,6 +6311,9 @@
 	    f = cd->ctor;
 	    f = f->overloadResolve(loc, arguments);
 	    checkDeprecated(sc, f);
+#if DMDV2
+	    checkPurity(sc, f);
+#endif
 	    e1 = new DotVarExp(e1->loc, e1, f);
 	    e1 = e1->semantic(sc);
 	    t1 = e1->type;
@@ -6062,7 +6349,7 @@
 	else if (e1->op == TOKtemplate)
 	{
 	    TemplateExp *te = (TemplateExp *)e1;
-	    f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments);
+	    f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments);
 	    if (!f)
 	    {	type = Type::terror;
 		return this;
@@ -6118,6 +6405,9 @@
 
 	f = f->overloadResolve(loc, arguments);
 	checkDeprecated(sc, f);
+#if DMDV2
+	checkPurity(sc, f);
+#endif
 
 	if (f->needThis() && hasThis(sc))
 	{
@@ -6165,9 +6455,75 @@
 
 int CallExp::checkSideEffect(int flag)
 {
+#if DMDV2
+    if (flag != 2)
+	return 1;
+
+    if (e1->checkSideEffect(2))
+	return 1;
+
+    /* If any of the arguments have side effects, this expression does
+     */
+    for (size_t i = 0; i < arguments->dim; i++)
+    {   Expression *e = (Expression *)arguments->data[i];
+
+	if (e->checkSideEffect(2))
+	    return 1;
+    }
+
+    /* If calling a function or delegate that is typed as pure,
+     * then this expression has no side effects.
+     */
+    Type *t = e1->type->toBasetype();
+    if (t->ty == Tfunction && ((TypeFunction *)t)->ispure)
+	return 0;
+    if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure)
+	return 0;
+#endif
     return 1;
 }
 
+#if DMDV2
+int CallExp::canThrow()
+{
+    if (e1->canThrow())
+	return 1;
+
+    /* If any of the arguments can throw, then this expression can throw
+     */
+    for (size_t i = 0; i < arguments->dim; i++)
+    {   Expression *e = (Expression *)arguments->data[i];
+
+	if (e->canThrow())
+	    return 1;
+    }
+
+    /* If calling a function or delegate that is typed as nothrow,
+     * then this expression cannot throw.
+     * Note that pure functions can throw.
+     */
+    Type *t = e1->type->toBasetype();
+    if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
+	return 0;
+    if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
+	return 0;
+
+    return 1;
+}
+#endif
+
+#if DMDV2
+int CallExp::isLvalue()
+{
+    if (type->toBasetype()->ty == Tstruct)
+	return 1;
+    Type *tb = e1->type->toBasetype();
+    if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
+	return 1;		// function returns a reference
+    return 0;
+}
+#endif
+
 Expression *CallExp::toLvalue(Scope *sc, Expression *e)
 {
     if (type->toBasetype()->ty == Tstruct)
@@ -6309,6 +6665,13 @@
     return this;
 }
 
+#if DMDV2
+int PtrExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *PtrExp::toLvalue(Scope *sc, Expression *e)
 {
 #if 0
@@ -6321,6 +6684,21 @@
     return this;
 }
 
+#if DMDV2
+Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars());
+
+    if (e1->op == TOKsymoff)
+    {	SymOffExp *se = (SymOffExp *)e1;
+	se->var->checkModify(loc, sc, type);
+	//return toLvalue(sc, e);
+    }
+
+    return Expression::modifiableLvalue(sc, e);
+}
+#endif
+
 void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writeByte('*');
@@ -6553,6 +6931,17 @@
     to = t;
 }
 
+#if DMDV2
+/* For cast(const) and cast(immutable)
+ */
+CastExp::CastExp(Loc loc, Expression *e, unsigned mod)
+	: UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+    to = NULL;
+    this->mod = mod;
+}
+#endif
+
 Expression *CastExp::syntaxCopy()
 {
     return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy());
@@ -6637,7 +7026,35 @@
 void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("cast(");
+#if DMDV1
     to->toCBuffer(buf, NULL, hgs);
+#else
+    if (to)
+	to->toCBuffer(buf, NULL, hgs);
+    else
+    {
+	switch (mod)
+	{   case 0:
+		break;
+	    case MODconst:
+		buf->writestring(Token::tochars[TOKconst]);
+		break;
+	    case MODinvariant:
+		buf->writestring(Token::tochars[TOKimmutable]);
+		break;
+	    case MODshared:
+		buf->writestring(Token::tochars[TOKshared]);
+		break;
+	    case MODshared | MODconst:
+		buf->writestring(Token::tochars[TOKshared]);
+		buf->writeByte(' ');
+		buf->writestring(Token::tochars[TOKconst]);
+		break;
+	    default:
+		assert(0);
+	}
+    }
+#endif
     buf->writeByte(')');
     expToCBuffer(buf, hgs, e1, precedence[op]);
 }
@@ -6831,6 +7248,13 @@
     e1->checkEscape();
 }
 
+#if DMDV2
+int SliceExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
 {
     return this;
@@ -6945,6 +7369,14 @@
     return e;
 }
 
+#if DMDV2
+int ArrayExp::isLvalue()
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+	return 0;
+    return 1;
+}
+#endif
 
 Expression *ArrayExp::toLvalue(Scope *sc, Expression *e)
 {
@@ -7015,6 +7447,13 @@
     e2->checkEscape();
 }
 
+#if DMDV2
+int CommaExp::isLvalue()
+{
+    return e2->isLvalue();
+}
+#endif
+
 Expression *CommaExp::toLvalue(Scope *sc, Expression *e)
 {
     e2 = e2->toLvalue(sc, NULL);
@@ -7181,6 +7620,13 @@
     return e;
 }
 
+#if DMDV2
+int IndexExp::isLvalue()
+{
+    return 1;
+}
+#endif
+
 Expression *IndexExp::toLvalue(Scope *sc, Expression *e)
 {
 //    if (type && type->toBasetype()->ty == Tvoid)
@@ -9034,9 +9480,21 @@
 		break;
 	}
     }
+#if 0
+    printf("res: %s\n", type->toChars());
+    printf("e1 : %s\n", e1->type->toChars());
+    printf("e2 : %s\n", e2->type->toChars());
+#endif
     return this;
 }
 
+#if DMDV2
+int CondExp::isLvalue()
+{
+    return e1->isLvalue() && e2->isLvalue();
+}
+#endif
+
 Expression *CondExp::toLvalue(Scope *sc, Expression *ex)
 {
     PtrExp *e;
@@ -9092,6 +9550,13 @@
     }
 }
 
+#if DMDV2
+int CondExp::canThrow()
+{
+    return econd->canThrow() || e1->canThrow() || e2->canThrow();
+}
+#endif
+
 void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     expToCBuffer(buf, hgs, econd, PREC_oror);
--- a/dmd/expression.h	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/expression.h	Tue Jan 06 16:33:51 2009 +0100
@@ -825,14 +825,11 @@
     Expression *semantic(Scope *sc);
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     void dump(int indent);
     elem *toElem(IRState *irs);
-
-    //LDC: since we don't convert abc.def -> *(&abc + ABC.def.offsetof)
-    // these are needed
-    Expression *optimize(int result);
-    Expression *interpret(InterState *istate);
 };
 
 struct DotTemplateInstanceExp : UnaExp
--- a/dmd/func.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/func.c	Tue Jan 06 16:33:51 2009 +0100
@@ -310,6 +310,8 @@
 
 		if (isFinal())
 		{
+		    if (isOverride())
+			error("does not override any function");
 		    cd->vtblFinal.push(this);
 		}
 		else
@@ -999,7 +1001,6 @@
 	    }
 
 	    int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE;
-	    //int offend = fbody ? fbody->fallOffEnd() : TRUE;
 
 	    if (isStaticCtorDeclaration())
 	    {	/* It's a static constructor. Ensure that all
--- a/dmd/import.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/import.c	Tue Jan 06 16:33:51 2009 +0100
@@ -112,7 +112,6 @@
     }
     if (!pkg)
 	pkg = mod;
-    mod->semantic();
 
     //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
 }
@@ -136,6 +135,12 @@
 	}
 #endif
 
+	// Modules need a list of each imported module
+	//printf("%s imports %s\n", sc->module->toChars(), mod->toChars());
+	sc->module->aimports.push(mod);
+
+	mod->semantic();
+
 	/* Default to private importing
 	 */
 	protection = sc->protection;
@@ -147,9 +152,6 @@
 	    sc->scopesym->importScope(mod, protection);
 	}
 
-	// Modules need a list of each imported module
-	sc->module->aimports.push(mod);
-
 	if (mod->needmoduleinfo)
 	    sc->module->needmoduleinfo = 1;
 
@@ -224,7 +226,9 @@
     //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
 
     if (!pkg)
-	load(NULL);
+    {	load(NULL);
+	mod->semantic();
+    }
 
     // Forward it to the package/module
     return pkg->search(loc, ident, flags);
--- a/dmd/interpret.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/interpret.c	Tue Jan 06 16:33:51 2009 +0100
@@ -1,2231 +1,2304 @@
-
-// 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 "mem.h"
-
-#include "statement.h"
-#include "expression.h"
-#include "cond.h"
-#include "init.h"
-#include "staticassert.h"
-#include "mtype.h"
-#include "scope.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-
-#define LOG	0
-
-struct InterState
-{
-    InterState *caller;		// calling function's InterState
-    FuncDeclaration *fd;	// function being interpreted
-    Dsymbols vars;		// variables used in this function
-    Statement *start;		// if !=NULL, start execution at this statement
-    Statement *gotoTarget;	// target of EXP_GOTO_INTERPRET result
-
-    InterState();
-};
-
-InterState::InterState()
-{
-    memset(this, 0, sizeof(InterState));
-}
-
-Expression *interpret_aaLen(InterState *istate, Expressions *arguments);
-Expression *interpret_aaKeys(InterState *istate, Expressions *arguments);
-Expression *interpret_aaValues(InterState *istate, Expressions *arguments);
-
-/*************************************
- * Attempt to interpret a function given the arguments.
- * Input:
- *	istate	state for calling function (NULL if none)
- * Return result expression if successful, NULL if not.
- */
-
-Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments)
-{
-#if LOG
-    printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars());
-    printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun);
-#endif
-    if (global.errors)
-	return NULL;
-    if (ident == Id::aaLen)
-	return interpret_aaLen(istate, arguments);
-    else if (ident == Id::aaKeys)
-	return interpret_aaKeys(istate, arguments);
-    else if (ident == Id::aaValues)
-	return interpret_aaValues(istate, arguments);
-
-    if (cantInterpret || semanticRun == 1)
-	return NULL;
-
-    if (needThis() || isNested() || !fbody)
-    {	cantInterpret = 1;
-	return NULL;
-    }
-
-    if (semanticRun == 0 && scope)
-    {
-	semantic3(scope);
-    if (global.errors)  // if errors compiling this function
-        return NULL;
-    }
-    if (semanticRun < 2)
-	return NULL;
-
-    Type *tb = type->toBasetype();
-    assert(tb->ty == Tfunction);
-    TypeFunction *tf = (TypeFunction *)tb;
-    Type *tret = tf->next->toBasetype();
-    if (tf->varargs /*|| tret->ty == Tvoid*/)
-    {	cantInterpret = 1;
-	return NULL;
-    }
-
-    if (tf->parameters)
-    {	size_t dim = Argument::dim(tf->parameters);
-	for (size_t i = 0; i < dim; i++)
-	{   Argument *arg = Argument::getNth(tf->parameters, i);
-	    if (arg->storageClass & STClazy)
-	    {   cantInterpret = 1;
-		return NULL;
-	    }
-	}
-    }
-
-    InterState istatex;
-    istatex.caller = istate;
-    istatex.fd = this;
-
-    Expressions vsave;		// place to save previous parameter values
-    size_t dim = 0;
-    if (arguments)
-    {
-	dim = arguments->dim;
-	assert(!dim || parameters->dim == dim);
-	vsave.setDim(dim);
-
-	/* Evaluate all the arguments to the function,
-	 * store the results in eargs[]
-	 */
-	Expressions eargs;
-	eargs.setDim(dim);
-
-	for (size_t i = 0; i < dim; i++)
-	{   Expression *earg = (Expression *)arguments->data[i];
-	    Argument *arg = Argument::getNth(tf->parameters, i);
-
-	    if (arg->storageClass & (STCout | STCref))
-	    {
-	    }
-	    else
-	    {	/* Value parameters
-		 */
-		Type *ta = arg->type->toBasetype();
-		if (ta->ty == Tsarray && earg->op == TOKaddress)
-		{
-		    /* Static arrays are passed by a simple pointer.
-		     * Skip past this to get at the actual arg.
-		     */
-		    earg = ((AddrExp *)earg)->e1;
-		}
-		earg = earg->interpret(istate ? istate : &istatex);
-		if (earg == EXP_CANT_INTERPRET)
-		    return NULL;
-	    }
-	    eargs.data[i] = earg;
-	}
-
-	for (size_t i = 0; i < dim; i++)
-	{   Expression *earg = (Expression *)eargs.data[i];
-	    Argument *arg = Argument::getNth(tf->parameters, i);
-	    VarDeclaration *v = (VarDeclaration *)parameters->data[i];
-	    vsave.data[i] = v->value;
-#if LOG
-	    printf("arg[%d] = %s\n", i, earg->toChars());
-#endif
-	    if (arg->storageClass & (STCout | STCref))
-	    {
-		/* Bind out or ref parameter to the corresponding
-		 * variable v2
-		 */
-		if (!istate || earg->op != TOKvar)
-		    return NULL;	// can't bind to non-interpreted vars
-
-		VarDeclaration *v2;
-		while (1)
-		{
-		    VarExp *ve = (VarExp *)earg;
-		    v2 = ve->var->isVarDeclaration();
-		    if (!v2)
-			return NULL;
-		    if (!v2->value || v2->value->op != TOKvar)
-			break;
-		    earg = v2->value;
-		}
-
-		v->value = new VarExp(earg->loc, v2);
-
-		/* Don't restore the value of v2 upon function return
-		 */
-		assert(istate);
-		for (size_t i = 0; i < istate->vars.dim; i++)
-		{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
-		    if (v == v2)
-		    {	istate->vars.data[i] = NULL;
-			break;
-		    }
-		}
-	    }
-	    else
-	    {	/* Value parameters
-		 */
-		v->value = earg;
-	    }
-#if LOG
-	    printf("interpreted arg[%d] = %s\n", i, earg->toChars());
-#endif
-	}
-    }
-
-    /* Save the values of the local variables used
-     */
-    Expressions valueSaves;
-    if (istate)
-    {
-	//printf("saving local variables...\n");
-	valueSaves.setDim(istate->vars.dim);
-	for (size_t i = 0; i < istate->vars.dim; i++)
-	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
-	    if (v)
-	    {
-		//printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
-		valueSaves.data[i] = v->value;
-		v->value = NULL;
-	    }
-	}
-    }
-
-    Expression *e = NULL;
-
-    while (1)
-    {
-	e = fbody->interpret(&istatex);
-	if (e == EXP_CANT_INTERPRET)
-	{
-#if LOG
-	    printf("function body failed to interpret\n");
-#endif
-	    e = NULL;
-	}
-
-	/* This is how we deal with a recursive statement AST
-	 * that has arbitrary goto statements in it.
-	 * Bubble up a 'result' which is the target of the goto
-	 * statement, then go recursively down the AST looking
-	 * for that statement, then execute starting there.
-	 */
-	if (e == EXP_GOTO_INTERPRET)
-	{
-	    istatex.start = istatex.gotoTarget;	// set starting statement
-	    istatex.gotoTarget = NULL;
-	}
-	else
-	    break;
-    }
-
-    /* Restore the parameter values
-     */
-    for (size_t i = 0; i < dim; i++)
-    {
-	VarDeclaration *v = (VarDeclaration *)parameters->data[i];
-	v->value = (Expression *)vsave.data[i];
-    }
-
-    if (istate)
-    {
-	/* Restore the variable values
-	 */
-	//printf("restoring local variables...\n");
-	for (size_t i = 0; i < istate->vars.dim; i++)
-	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
-	    if (v)
-	    {	v->value = (Expression *)valueSaves.data[i];
-		//printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
-	    }
-	}
-    }
-
-    return e;
-}
-
-/******************************** Statement ***************************/
-
-#define START()				\
-    if (istate->start)			\
-    {	if (istate->start != this)	\
-	    return NULL;		\
-	istate->start = NULL;		\
-    }
-
-/***********************************
- * Interpret the statement.
- * Returns:
- *	NULL	continue to next statement
- *	EXP_CANT_INTERPRET	cannot interpret statement at compile time
- *	!NULL	expression from return statement
- */
-
-Expression *Statement::interpret(InterState *istate)
-{
-#if LOG
-    printf("Statement::interpret()\n");
-#endif
-    START()
-    return EXP_CANT_INTERPRET;
-}
-
-Expression *ExpStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : "");
-#endif
-    START()
-    if (exp)
-    {
-	Expression *e = exp->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
-	{
-	    //printf("-ExpStatement::interpret(): %p\n", e);
-	    return EXP_CANT_INTERPRET;
-	}
-    }
-    return NULL;
-}
-
-Expression *CompoundStatement::interpret(InterState *istate)
-{   Expression *e = NULL;
-
-#if LOG
-    printf("CompoundStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (statements)
-    {
-	for (size_t i = 0; i < statements->dim; i++)
-	{   Statement *s = (Statement *)statements->data[i];
-
-	    if (s)
-	    {
-		e = s->interpret(istate);
-		if (e)
-		    break;
-	    }
-	}
-    }
-#if LOG
-    printf("-CompoundStatement::interpret() %p\n", e);
-#endif
-    return e;
-}
-
-Expression *UnrolledLoopStatement::interpret(InterState *istate)
-{   Expression *e = NULL;
-
-#if LOG
-    printf("UnrolledLoopStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (statements)
-    {
-	for (size_t i = 0; i < statements->dim; i++)
-	{   Statement *s = (Statement *)statements->data[i];
-
-	    e = s->interpret(istate);
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_CONTINUE_INTERPRET)
-	    {	e = NULL;
-		continue;
-	    }
-	    if (e == EXP_BREAK_INTERPRET)
-	    {	e = NULL;
-		break;
-	    }
-	    if (e)
-		break;
-	}
-    }
-    return e;
-}
-
-Expression *IfStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("IfStatement::interpret(%s)\n", condition->toChars());
-#endif
-
-    if (istate->start == this)
-	istate->start = NULL;
-    if (istate->start)
-    {
-	Expression *e = NULL;
-	if (ifbody)
-	    e = ifbody->interpret(istate);
-	if (istate->start && elsebody)
-	    e = elsebody->interpret(istate);
-	return e;
-    }
-
-    Expression *e = condition->interpret(istate);
-    assert(e);
-    //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n");
-    if (e != EXP_CANT_INTERPRET)
-    {
-	if (e->isBool(TRUE))
-	    e = ifbody ? ifbody->interpret(istate) : NULL;
-	else if (e->isBool(FALSE))
-	    e = elsebody ? elsebody->interpret(istate) : NULL;
-	else
-	{
-	    e = EXP_CANT_INTERPRET;
-	}
-    }
-    return e;
-}
-
-Expression *ScopeStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ScopeStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    return statement ? statement->interpret(istate) : NULL;
-}
-
-Expression *ReturnStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : "");
-#endif
-    START()
-    if (!exp)
-	return EXP_VOID_INTERPRET;
-#if LOG
-    Expression *e = exp->interpret(istate);
-    printf("e = %p\n", e);
-    return e;
-#else
-    return exp->interpret(istate);
-#endif
-}
-
-Expression *BreakStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("BreakStatement::interpret()\n");
-#endif
-    START()
-    if (ident)
-	return EXP_CANT_INTERPRET;
-    else
-	return EXP_BREAK_INTERPRET;
-}
-
-Expression *ContinueStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ContinueStatement::interpret()\n");
-#endif
-    START()
-    if (ident)
-	return EXP_CANT_INTERPRET;
-    else
-	return EXP_CONTINUE_INTERPRET;
-}
-
-Expression *WhileStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("WhileStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    Expression *e;
-
-    if (istate->start)
-    {
-	e = body ? body->interpret(istate) : NULL;
-	if (istate->start)
-	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
-	    return e;
-	if (e == EXP_BREAK_INTERPRET)
-	    return NULL;
-	if (e != EXP_CONTINUE_INTERPRET)
-	    return e;
-    }
-
-    while (1)
-    {
-	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
-	    break;
-	if (!e->isConst())
-	{   e = EXP_CANT_INTERPRET;
-	    break;
-	}
-	if (e->isBool(TRUE))
-	{   e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_CONTINUE_INTERPRET)
-		continue;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {	e = NULL;
-		break;
-	    }
-	    if (e)
-		break;
-	}
-	else if (e->isBool(FALSE))
-	{   e = NULL;
-	    break;
-	}
-	else
-	    assert(0);
-    }
-    return e;
-}
-
-Expression *DoStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("DoStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    Expression *e;
-
-    if (istate->start)
-    {
-	e = body ? body->interpret(istate) : NULL;
-	if (istate->start)
-	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
-	    return e;
-	if (e == EXP_BREAK_INTERPRET)
-	    return NULL;
-	if (e == EXP_CONTINUE_INTERPRET)
-	    goto Lcontinue;
-	if (e)
-	    return e;
-    }
-
-    while (1)
-    {
-	e = body ? body->interpret(istate) : NULL;
-	if (e == EXP_CANT_INTERPRET)
-	    break;
-	if (e == EXP_BREAK_INTERPRET)
-	{   e = NULL;
-	    break;
-	}
-	if (e && e != EXP_CONTINUE_INTERPRET)
-	    break;
-
-    Lcontinue:
-	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
-	    break;
-	if (!e->isConst())
-	{   e = EXP_CANT_INTERPRET;
-	    break;
-	}
-	if (e->isBool(TRUE))
-	{
-	}
-	else if (e->isBool(FALSE))
-	{   e = NULL;
-	    break;
-	}
-	else
-	    assert(0);
-    }
-    return e;
-}
-
-Expression *ForStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ForStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    Expression *e;
-
-    if (init)
-    {
-	e = init->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
-	    return e;
-	assert(!e);
-    }
-
-    if (istate->start)
-    {
-	e = body ? body->interpret(istate) : NULL;
-	if (istate->start)
-	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
-	    return e;
-	if (e == EXP_BREAK_INTERPRET)
-	    return NULL;
-	if (e == EXP_CONTINUE_INTERPRET)
-	    goto Lcontinue;
-	if (e)
-	    return e;
-    }
-
-    while (1)
-    {
-	if (!condition)
-	    goto Lhead;
-	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
-	    break;
-	if (!e->isConst())
-	{   e = EXP_CANT_INTERPRET;
-	    break;
-	}
-	if (e->isBool(TRUE))
-	{
-	Lhead:
-	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {   e = NULL;
-		break;
-	    }
-	    if (e && e != EXP_CONTINUE_INTERPRET)
-		break;
-	Lcontinue:
-	    if (increment)
-	    {
-		e = increment->interpret(istate);
-		if (e == EXP_CANT_INTERPRET)
-		    break;
-	    }
-	}
-	else if (e->isBool(FALSE))
-	{   e = NULL;
-	    break;
-	}
-	else
-	    assert(0);
-    }
-    return e;
-}
-
-Expression *ForeachStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ForeachStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (istate->start)
-	return NULL;
-
-    Expression *e = NULL;
-    Expression *eaggr;
-
-    if (value->isOut() || value->isRef())
-	return EXP_CANT_INTERPRET;
-
-    eaggr = aggr->interpret(istate);
-    if (eaggr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
-
-    Expression *dim = ArrayLength(Type::tsize_t, eaggr);
-    if (dim == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
-
-    Expression *keysave = key ? key->value : NULL;
-    Expression *valuesave = value->value;
-
-    uinteger_t d = dim->toUInteger();
-    uinteger_t index;
-
-    if (op == TOKforeach)
-    {
-	for (index = 0; index < d; index++)
-	{
-	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
-	    if (key)
-		key->value = ekey;
-	    e = Index(value->type, eaggr, ekey);
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    value->value = e;
-
-	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {   e = NULL;
-		break;
-	    }
-	    if (e == EXP_CONTINUE_INTERPRET)
-		e = NULL;
-	    else if (e)
-		break;
-	}
-    }
-    else // TOKforeach_reverse
-    {
-	for (index = d; index-- != 0;)
-	{
-	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
-	    if (key)
-		key->value = ekey;
-	    e = Index(value->type, eaggr, ekey);
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    value->value = e;
-
-	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {   e = NULL;
-		break;
-	    }
-	    if (e == EXP_CONTINUE_INTERPRET)
-		e = NULL;
-	    else if (e)
-		break;
-	}
-    }
-    value->value = valuesave;
-    if (key)
-	key->value = keysave;
-    return e;
-}
-
-#if DMDV2
-Expression *ForeachRangeStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("ForeachRangeStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (istate->start)
-	return NULL;
-
-    Expression *e = NULL;
-    Expression *elwr = lwr->interpret(istate);
-    if (elwr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
-
-    Expression *eupr = upr->interpret(istate);
-    if (eupr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
-
-    Expression *keysave = key->value;
-
-    if (op == TOKforeach)
-    {
-	key->value = elwr;
-
-	while (1)
-	{
-	    e = Cmp(TOKlt, key->value->type, key->value, upr);
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e->isBool(TRUE) == FALSE)
-	    {	e = NULL;
-		break;
-	    }
-
-	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {   e = NULL;
-		break;
-	    }
-	    e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    key->value = e;
-	}
-    }
-    else // TOKforeach_reverse
-    {
-	key->value = eupr;
-
-	while (1)
-	{
-	    e = Cmp(TOKgt, key->value->type, key->value, lwr);
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e->isBool(TRUE) == FALSE)
-	    {	e = NULL;
-		break;
-	    }
-
-	    e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    key->value = e;
-
-	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
-		break;
-	    if (e == EXP_BREAK_INTERPRET)
-	    {   e = NULL;
-		break;
-	    }
-	}
-    }
-    key->value = keysave;
-    return e;
-}
-#endif
-
-Expression *SwitchStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("SwitchStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    Expression *e = NULL;
-
-    if (istate->start)
-    {
-	e = body ? body->interpret(istate) : NULL;
-	if (istate->start)
-	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
-	    return e;
-	if (e == EXP_BREAK_INTERPRET)
-	    return NULL;
-	return e;
-    }
-
-
-    Expression *econdition = condition->interpret(istate);
-    if (econdition == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
-
-    Statement *s = NULL;
-    if (cases)
-    {
-	for (size_t i = 0; i < cases->dim; i++)
-	{
-	    CaseStatement *cs = (CaseStatement *)cases->data[i];
-	    e = Equal(TOKequal, Type::tint32, econdition, cs->exp);
-	    if (e == EXP_CANT_INTERPRET)
-		return EXP_CANT_INTERPRET;
-	    if (e->isBool(TRUE))
-	    {	s = cs;
-		break;
-	    }
-	}
-    }
-    if (!s)
-    {	if (hasNoDefault)
-	    error("no default or case for %s in switch statement", econdition->toChars());
-	s = sdefault;
-    }
-
-    assert(s);
-    istate->start = s;
-    e = body ? body->interpret(istate) : NULL;
-    assert(!istate->start);
-    if (e == EXP_BREAK_INTERPRET)
-	return NULL;
-    return e;
-}
-
-Expression *CaseStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this);
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (statement)
-	return statement->interpret(istate);
-    else
-	return NULL;
-}
-
-Expression *DefaultStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("DefaultStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    if (statement)
-	return statement->interpret(istate);
-    else
-	return NULL;
-}
-
-Expression *GotoStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("GotoStatement::interpret()\n");
-#endif
-    START()
-    assert(label && label->statement);
-    istate->gotoTarget = label->statement;
-    return EXP_GOTO_INTERPRET;
-}
-
-Expression *GotoCaseStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("GotoCaseStatement::interpret()\n");
-#endif
-    START()
-    assert(cs);
-    istate->gotoTarget = cs;
-    return EXP_GOTO_INTERPRET;
-}
-
-Expression *GotoDefaultStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("GotoDefaultStatement::interpret()\n");
-#endif
-    START()
-    assert(sw && sw->sdefault);
-    istate->gotoTarget = sw->sdefault;
-    return EXP_GOTO_INTERPRET;
-}
-
-Expression *LabelStatement::interpret(InterState *istate)
-{
-#if LOG
-    printf("LabelStatement::interpret()\n");
-#endif
-    if (istate->start == this)
-	istate->start = NULL;
-    return statement ? statement->interpret(istate) : NULL;
-}
-
-/******************************** Expression ***************************/
-
-Expression *Expression::interpret(InterState *istate)
-{
-#if LOG
-    printf("Expression::interpret() %s\n", toChars());
-    printf("type = %s\n", type->toChars());
-    dump(0);
-#endif
-    return EXP_CANT_INTERPRET;
-}
-
-Expression *NullExp::interpret(InterState *istate)
-{
-    return this;
-}
-
-Expression *IntegerExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("IntegerExp::interpret() %s\n", toChars());
-#endif
-    return this;
-}
-
-Expression *RealExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("RealExp::interpret() %s\n", toChars());
-#endif
-    return this;
-}
-
-Expression *ComplexExp::interpret(InterState *istate)
-{
-    return this;
-}
-
-Expression *StringExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("StringExp::interpret() %s\n", toChars());
-#endif
-    return this;
-}
-
-Expression *getVarExp(Loc loc, InterState *istate, Declaration *d)
-{
-    Expression *e = EXP_CANT_INTERPRET;
-    VarDeclaration *v = d->isVarDeclaration();
-    SymbolDeclaration *s = d->isSymbolDeclaration();
-    if (v)
-    {
-#if DMDV2
-	if ((v->isConst() || v->isInvariant()) && v->init && !v->value)
-#else
-	if (v->isConst() && v->init)
-#endif
-	{   e = v->init->toExpression();
-	    if (e && !e->type)
-		e->type = v->type;
-	}
-	else
-	{   e = v->value;
-	    if (!e)
-		error(loc, "variable %s is used before initialization", v->toChars());
-	    else if (e != EXP_CANT_INTERPRET)
-		e = e->interpret(istate);
-	}
-	if (!e)
-	    e = EXP_CANT_INTERPRET;
-    }
-    else if (s)
-    {
-	if (s->dsym->toInitializer() == s->sym)
-	{   Expressions *exps = new Expressions();
-	    e = new StructLiteralExp(0, s->dsym, exps);
-	    e = e->semantic(NULL);
-	}
-    }
-    return e;
-}
-
-Expression *VarExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("VarExp::interpret() %s\n", toChars());
-#endif
-    return getVarExp(loc, istate, var);
-}
-
-Expression *DeclarationExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("DeclarationExp::interpret() %s\n", toChars());
-#endif
-    Expression *e;
-    VarDeclaration *v = declaration->isVarDeclaration();
-    if (v)
-    {
-	Dsymbol *s = v->toAlias();
-	if (s == v && !v->isStatic() && v->init)
-	{
-	    ExpInitializer *ie = v->init->isExpInitializer();
-	    if (ie)
-		e = ie->exp->interpret(istate);
-	    else if (v->init->isVoidInitializer())
-		e = NULL;
-	}
-#if DMDV2
-	else if (s == v && (v->isConst() || v->isInvariant()) && v->init)
-#else
-	else if (s == v && v->isConst() && v->init)
-#endif
-	{   e = v->init->toExpression();
-	    if (!e)
-		e = EXP_CANT_INTERPRET;
-	    else if (!e->type)
-		e->type = v->type;
-	}
-    }
-    else if (declaration->isAttribDeclaration() ||
-	     declaration->isTemplateMixin() ||
-	     declaration->isTupleDeclaration())
-    {	// These can be made to work, too lazy now
-	e = EXP_CANT_INTERPRET;
-    }
-    else
-    {	// Others should not contain executable code, so are trivial to evaluate
-	e = NULL;
-    }
-#if LOG
-    printf("-DeclarationExp::interpret(): %p\n", e);
-#endif
-    return e;
-}
-
-Expression *TupleExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("TupleExp::interpret() %s\n", toChars());
-#endif
-    Expressions *expsx = NULL;
-
-    for (size_t i = 0; i < exps->dim; i++)
-    {   Expression *e = (Expression *)exps->data[i];
-	Expression *ex;
-
-	ex = e->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
-	{   delete expsx;
-	    return ex;
-	}
-
-	/* If any changes, do Copy On Write
-	 */
-	if (ex != e)
-	{
-	    if (!expsx)
-	    {	expsx = new Expressions();
-		expsx->setDim(exps->dim);
-		for (size_t j = 0; j < i; j++)
-		{
-		    expsx->data[j] = exps->data[j];
-		}
-	    }
-	    expsx->data[i] = (void *)ex;
-	}
-    }
-    if (expsx)
-    {	TupleExp *te = new TupleExp(loc, expsx);
-	expandTuples(te->exps);
-	te->type = new TypeTuple(te->exps);
-	return te;
-    }
-    return this;
-}
-
-Expression *ArrayLiteralExp::interpret(InterState *istate)
-{   Expressions *expsx = NULL;
-
-#if LOG
-    printf("ArrayLiteralExp::interpret() %s\n", toChars());
-#endif
-    if (elements)
-    {
-	for (size_t i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    Expression *ex;
-
-	    ex = e->interpret(istate);
-	    if (ex == EXP_CANT_INTERPRET)
-	    {   delete expsx;
-		return EXP_CANT_INTERPRET;
-	    }
-
-	    /* If any changes, do Copy On Write
-	     */
-	    if (ex != e)
-	    {
-		if (!expsx)
-		{   expsx = new Expressions();
-		    expsx->setDim(elements->dim);
-		    for (size_t j = 0; j < elements->dim; j++)
-		    {
-			expsx->data[j] = elements->data[j];
-		    }
-		}
-		expsx->data[i] = (void *)ex;
-	    }
-	}
-    }
-    if (elements && expsx)
-    {
-	expandTuples(expsx);
-	if (expsx->dim != elements->dim)
-	{   delete expsx;
-	    return EXP_CANT_INTERPRET;
-	}
-	ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx);
-	ae->type = type;
-	return ae;
-    }
-    return this;
-}
-
-Expression *AssocArrayLiteralExp::interpret(InterState *istate)
-{   Expressions *keysx = keys;
-    Expressions *valuesx = values;
-
-#if LOG
-    printf("AssocArrayLiteralExp::interpret() %s\n", toChars());
-#endif
-    for (size_t i = 0; i < keys->dim; i++)
-    {   Expression *ekey = (Expression *)keys->data[i];
-	Expression *evalue = (Expression *)values->data[i];
-	Expression *ex;
-
-	ex = ekey->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
-	    goto Lerr;
-
-	/* If any changes, do Copy On Write
-	 */
-	if (ex != ekey)
-	{
-	    if (keysx == keys)
-		keysx = (Expressions *)keys->copy();
-	    keysx->data[i] = (void *)ex;
-	}
-
-	ex = evalue->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
-	    goto Lerr;
-
-	/* If any changes, do Copy On Write
-	 */
-	if (ex != evalue)
-	{
-	    if (valuesx == values)
-		valuesx = (Expressions *)values->copy();
-	    valuesx->data[i] = (void *)ex;
-	}
-    }
-    if (keysx != keys)
-	expandTuples(keysx);
-    if (valuesx != values)
-	expandTuples(valuesx);
-    if (keysx->dim != valuesx->dim)
-	goto Lerr;
-
-    /* Remove duplicate keys
-     */
-    for (size_t i = 1; i < keysx->dim; i++)
-    {   Expression *ekey = (Expression *)keysx->data[i - 1];
-
-	for (size_t j = i; j < keysx->dim; j++)
-	{   Expression *ekey2 = (Expression *)keysx->data[j];
-	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
-	    if (ex == EXP_CANT_INTERPRET)
-		goto Lerr;
-	    if (ex->isBool(TRUE))	// if a match
-	    {
-		// Remove ekey
-		if (keysx == keys)
-		    keysx = (Expressions *)keys->copy();
-		if (valuesx == values)
-		    valuesx = (Expressions *)values->copy();
-		keysx->remove(i - 1);
-		valuesx->remove(i - 1);
-		i -= 1;		// redo the i'th iteration
-		break;
-	    }
-	}
-    }
-
-    if (keysx != keys || valuesx != values)
-    {
-	AssocArrayLiteralExp *ae;
-	ae = new AssocArrayLiteralExp(loc, keysx, valuesx);
-	ae->type = type;
-	return ae;
-    }
-    return this;
-
-Lerr:
-    if (keysx != keys)
-	delete keysx;
-    if (valuesx != values)
-	delete values;
-    return EXP_CANT_INTERPRET;
-}
-
-Expression *StructLiteralExp::interpret(InterState *istate)
-{   Expressions *expsx = NULL;
-
-#if LOG
-    printf("StructLiteralExp::interpret() %s\n", toChars());
-#endif
-    /* We don't know how to deal with overlapping fields
-     */
-    if (sd->hasUnions)
-	return EXP_CANT_INTERPRET;
-
-    if (elements)
-    {
-	for (size_t i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    if (!e)
-		continue;
-
-	    Expression *ex = e->interpret(istate);
-	    if (ex == EXP_CANT_INTERPRET)
-	    {   delete expsx;
-		return EXP_CANT_INTERPRET;
-	    }
-
-	    /* If any changes, do Copy On Write
-	     */
-	    if (ex != e)
-	    {
-		if (!expsx)
-		{   expsx = new Expressions();
-		    expsx->setDim(elements->dim);
-		    for (size_t j = 0; j < elements->dim; j++)
-		    {
-			expsx->data[j] = elements->data[j];
-		    }
-		}
-		expsx->data[i] = (void *)ex;
-	    }
-	}
-    }
-    if (elements && expsx)
-    {
-	expandTuples(expsx);
-	if (expsx->dim != elements->dim)
-	{   delete expsx;
-	    return EXP_CANT_INTERPRET;
-	}
-	StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx);
-	se->type = type;
-	return se;
-    }
-    return this;
-}
-
-Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *))
-{   Expression *e;
-    Expression *e1;
-
-#if LOG
-    printf("UnaExp::interpretCommon() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e1->isConst() != 1)
-	goto Lcant;
-
-    e = (*fp)(type, e1);
-    return e;
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-#define UNA_INTERPRET(op) \
-Expression *op##Exp::interpret(InterState *istate)	\
-{							\
-    return interpretCommon(istate, &op);		\
-}
-
-UNA_INTERPRET(Neg)
-UNA_INTERPRET(Com)
-UNA_INTERPRET(Not)
-UNA_INTERPRET(Bool)
-
-
-typedef Expression *(*fp_t)(Type *, Expression *, Expression *);
-
-Expression *BinExp::interpretCommon(InterState *istate, fp_t fp)
-{   Expression *e;
-    Expression *e1;
-    Expression *e2;
-
-#if LOG
-    printf("BinExp::interpretCommon() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e1->isConst() != 1)
-	goto Lcant;
-
-    e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e2->isConst() != 1)
-	goto Lcant;
-
-    e = (*fp)(type, e1, e2);
-    return e;
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-#define BIN_INTERPRET(op) \
-Expression *op##Exp::interpret(InterState *istate)	\
-{							\
-    return interpretCommon(istate, &op);		\
-}
-
-BIN_INTERPRET(Add)
-BIN_INTERPRET(Min)
-BIN_INTERPRET(Mul)
-BIN_INTERPRET(Div)
-BIN_INTERPRET(Mod)
-BIN_INTERPRET(Shl)
-BIN_INTERPRET(Shr)
-BIN_INTERPRET(Ushr)
-BIN_INTERPRET(And)
-BIN_INTERPRET(Or)
-BIN_INTERPRET(Xor)
-
-
-typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);
-
-Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp)
-{   Expression *e;
-    Expression *e1;
-    Expression *e2;
-
-#if LOG
-    printf("BinExp::interpretCommon2() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e1->isConst() != 1 &&
-	e1->op != TOKnull &&
-	e1->op != TOKstring &&
-	e1->op != TOKarrayliteral &&
-	e1->op != TOKstructliteral)
-	goto Lcant;
-
-    e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e2->isConst() != 1 &&
-	e2->op != TOKnull &&
-	e2->op != TOKstring &&
-	e2->op != TOKarrayliteral &&
-	e2->op != TOKstructliteral)
-	goto Lcant;
-
-    e = (*fp)(op, type, e1, e2);
-    return e;
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-#define BIN_INTERPRET2(op) \
-Expression *op##Exp::interpret(InterState *istate)	\
-{							\
-    return interpretCommon2(istate, &op);		\
-}
-
-BIN_INTERPRET2(Equal)
-BIN_INTERPRET2(Identity)
-BIN_INTERPRET2(Cmp)
-
-Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
-{
-#if LOG
-    printf("BinExp::interpretAssignCommon() %s\n", toChars());
-#endif
-    Expression *e = EXP_CANT_INTERPRET;
-    Expression *e1 = this->e1;
-
-    if (fp)
-    {
-	if (e1->op == TOKcast)
-	{   CastExp *ce = (CastExp *)e1;
-	    e1 = ce->e1;
-	}
-    }
-    if (e1 == EXP_CANT_INTERPRET)
-	return e1;
-    Expression *e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
-	return e2;
-
-    /* Assignment to variable of the form:
-     *	v = e2
-     */
-    if (e1->op == TOKvar)
-    {
-	VarExp *ve = (VarExp *)e1;
-	VarDeclaration *v = ve->var->isVarDeclaration();
-	if (v && !v->isDataseg())
-	{
-	    /* Chase down rebinding of out and ref
-	     */
-	    if (v->value && v->value->op == TOKvar)
-	    {
-		VarExp *ve2 = (VarExp *)v->value;
-		if (ve2->var->isSymbolDeclaration())
-		{
-		    /* This can happen if v is a struct initialized to
-		     * 0 using an __initZ SymbolDeclaration from
-		     * TypeStruct::defaultInit()
-		     */
-		}
-		else
-		    v = ve2->var->isVarDeclaration();
-		assert(v);
-	    }
-
-	    Expression *ev = v->value;
-	    if (fp && !ev)
-	    {	error("variable %s is used before initialization", v->toChars());
-		return e;
-	    }
-	    if (fp)
-		e2 = (*fp)(v->type, ev, e2);
-	    else
-	    {	/* Look for special case of struct being initialized with 0.
-		 */
-		if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64)
-		{
-		    e2 = v->type->defaultInit();
-		}
-		e2 = Cast(v->type, v->type, e2);
-	    }
-	    if (e2 != EXP_CANT_INTERPRET)
-	    {
-		if (!v->isParameter())
-		{
-		    for (size_t i = 0; 1; i++)
-		    {
-			if (i == istate->vars.dim)
-			{   istate->vars.push(v);
-			    //printf("\tadding %s to istate\n", v->toChars());
-			    break;
-			}
-			if (v == (VarDeclaration *)istate->vars.data[i])
-			    break;
-		    }
-		}
-		v->value = e2;
-		e = Cast(type, type, post ? ev : e2);
-	    }
-	}
-    }
-    /* Assignment to struct member of the form:
-     *   *(symoffexp) = e2
-     */
-    else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff)
-    {	SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
-	VarDeclaration *v = soe->var->isVarDeclaration();
-
-	if (v->isDataseg())
-	    return EXP_CANT_INTERPRET;
-	if (fp && !v->value)
-	{   error("variable %s is used before initialization", v->toChars());
-	    return e;
-	}
-	Expression *vie = v->value;
-	if (vie->op == TOKvar)
-	{
-	    Declaration *d = ((VarExp *)vie)->var;
-	    vie = getVarExp(e1->loc, istate, d);
-	}
-	if (vie->op != TOKstructliteral)
-	    return EXP_CANT_INTERPRET;
-	StructLiteralExp *se = (StructLiteralExp *)vie;
-	int fieldi = se->getFieldIndex(type, soe->offset);
-	if (fieldi == -1)
-	    return EXP_CANT_INTERPRET;
-	Expression *ev = se->getField(type, soe->offset);
-	if (fp)
-	    e2 = (*fp)(type, ev, e2);
-	else
-	    e2 = Cast(type, type, e2);
-	if (e2 == EXP_CANT_INTERPRET)
-	    return e2;
-
-	if (!v->isParameter())
-	{
-	    for (size_t i = 0; 1; i++)
-	    {
-		if (i == istate->vars.dim)
-		{   istate->vars.push(v);
-		    break;
-		}
-		if (v == (VarDeclaration *)istate->vars.data[i])
-		    break;
-	    }
-	}
-
-	/* Create new struct literal reflecting updated fieldi
-	 */
-	Expressions *expsx = new Expressions();
-	expsx->setDim(se->elements->dim);
-	for (size_t j = 0; j < expsx->dim; j++)
-	{
-	    if (j == fieldi)
-		expsx->data[j] = (void *)e2;
-	    else
-		expsx->data[j] = se->elements->data[j];
-	}
-	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
-	v->value->type = se->type;
-
-	e = Cast(type, type, post ? ev : e2);
-    }
-    /* Assignment to array element of the form:
-     *   a[i] = e2
-     */
-    else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar)
-    {	IndexExp *ie = (IndexExp *)e1;
-	VarExp *ve = (VarExp *)ie->e1;
-	VarDeclaration *v = ve->var->isVarDeclaration();
-
-	if (!v || v->isDataseg())
-	    return EXP_CANT_INTERPRET;
-	if (!v->value)
-	{
-	    if (fp)
-	    {   error("variable %s is used before initialization", v->toChars());
-		return e;
-	    }
-
-	    Type *t = v->type->toBasetype();
-	    if (t->ty == Tsarray)
-	    {
-		/* This array was void initialized. Create a
-		 * default initializer for it.
-		 * What we should do is fill the array literal with
-		 * NULL data, so use-before-initialized can be detected.
-		 * But we're too lazy at the moment to do it, as that
-		 * involves redoing Index() and whoever calls it.
-		 */
-		Expression *ev = v->type->defaultInit();
-		size_t dim = ((TypeSArray *)t)->dim->toInteger();
-		Expressions *elements = new Expressions();
-		elements->setDim(dim);
-		for (size_t i = 0; i < dim; i++)
-		    elements->data[i] = (void *)ev;
-		ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
-		ae->type = v->type;
-		v->value = ae;
-	    }
-	    else
-		return EXP_CANT_INTERPRET;
-	}
-
-	ArrayLiteralExp *ae = NULL;
-	AssocArrayLiteralExp *aae = NULL;
-	StringExp *se = NULL;
-	if (v->value->op == TOKarrayliteral)
-	    ae = (ArrayLiteralExp *)v->value;
-	else if (v->value->op == TOKassocarrayliteral)
-	    aae = (AssocArrayLiteralExp *)v->value;
-	else if (v->value->op == TOKstring)
-	    se = (StringExp *)v->value;
-	else
-	    return EXP_CANT_INTERPRET;
-
-	Expression *index = ie->e2->interpret(istate);
-	if (index == EXP_CANT_INTERPRET)
-	    return EXP_CANT_INTERPRET;
-	Expression *ev;
-	if (fp || ae || se)	// not for aae, because key might not be there
-	{
-	    ev = Index(type, v->value, index);
-	    if (ev == EXP_CANT_INTERPRET)
-		return EXP_CANT_INTERPRET;
-	}
-
-	if (fp)
-	    e2 = (*fp)(type, ev, e2);
-	else
-	    e2 = Cast(type, type, e2);
-	if (e2 == EXP_CANT_INTERPRET)
-	    return e2;
-
-	if (!v->isParameter())
-	{
-	    for (size_t i = 0; 1; i++)
-	    {
-		if (i == istate->vars.dim)
-		{   istate->vars.push(v);
-		    break;
-		}
-		if (v == (VarDeclaration *)istate->vars.data[i])
-		    break;
-	    }
-	}
-
-	if (ae)
-	{
-	    /* Create new array literal reflecting updated elem
-	     */
-	    int elemi = index->toInteger();
-	    Expressions *expsx = new Expressions();
-	    expsx->setDim(ae->elements->dim);
-	    for (size_t j = 0; j < expsx->dim; j++)
-	    {
-		if (j == elemi)
-		    expsx->data[j] = (void *)e2;
-		else
-		    expsx->data[j] = ae->elements->data[j];
-	    }
-	    v->value = new ArrayLiteralExp(ae->loc, expsx);
-	    v->value->type = ae->type;
-	}
-	else if (aae)
-	{
-	    /* Create new associative array literal reflecting updated key/value
-	     */
-	    Expressions *keysx = aae->keys;
-	    Expressions *valuesx = new Expressions();
-	    valuesx->setDim(aae->values->dim);
-	    int updated = 0;
-	    for (size_t j = valuesx->dim; j; )
-	    {	j--;
-		Expression *ekey = (Expression *)aae->keys->data[j];
-		Expression *ex = Equal(TOKequal, Type::tbool, ekey, index);
-		if (ex == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
-		if (ex->isBool(TRUE))
-		{   valuesx->data[j] = (void *)e2;
-		    updated = 1;
-		}
-		else
-		    valuesx->data[j] = aae->values->data[j];
-	    }
-	    if (!updated)
-	    {	// Append index/e2 to keysx[]/valuesx[]
-		valuesx->push(e2);
-		keysx = (Expressions *)keysx->copy();
-		keysx->push(index);
-	    }
-	    v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx);
-	    v->value->type = aae->type;
-	}
-	else if (se)
-	{
-	    /* Create new string literal reflecting updated elem
-	     */
-	    int elemi = index->toInteger();
-	    unsigned char *s;
-	    s = (unsigned char *)mem.calloc(se->len + 1, se->sz);
-	    memcpy(s, se->string, se->len * se->sz);
-	    unsigned value = e2->toInteger();
-	    switch (se->sz)
-	    {
-		case 1:	s[elemi] = value; break;
-		case 2:	((unsigned short *)s)[elemi] = value; break;
-		case 4:	((unsigned *)s)[elemi] = value; break;
-		default:
-		    assert(0);
-		    break;
-	    }
-	    StringExp *se2 = new StringExp(se->loc, s, se->len);
-	    se2->committed = se->committed;
-	    se2->postfix = se->postfix;
-	    se2->type = se->type;
-	    v->value = se2;
-	}
-	else
-	    assert(0);
-
-	e = Cast(type, type, post ? ev : e2);
-    }
-    else
-    {
-#ifdef DEBUG
-	dump(0);
-#endif
-    }
-    return e;
-}
-
-Expression *AssignExp::interpret(InterState *istate)
-{
-    return interpretAssignCommon(istate, NULL);
-}
-
-#define BIN_ASSIGN_INTERPRET(op) \
-Expression *op##AssignExp::interpret(InterState *istate)	\
-{								\
-    return interpretAssignCommon(istate, &op);			\
-}
-
-BIN_ASSIGN_INTERPRET(Add)
-BIN_ASSIGN_INTERPRET(Min)
-BIN_ASSIGN_INTERPRET(Cat)
-BIN_ASSIGN_INTERPRET(Mul)
-BIN_ASSIGN_INTERPRET(Div)
-BIN_ASSIGN_INTERPRET(Mod)
-BIN_ASSIGN_INTERPRET(Shl)
-BIN_ASSIGN_INTERPRET(Shr)
-BIN_ASSIGN_INTERPRET(Ushr)
-BIN_ASSIGN_INTERPRET(And)
-BIN_ASSIGN_INTERPRET(Or)
-BIN_ASSIGN_INTERPRET(Xor)
-
-Expression *PostExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("PostExp::interpret() %s\n", toChars());
-#endif
-    Expression *e;
-    if (op == TOKplusplus)
-	e = interpretAssignCommon(istate, &Add, 1);
-    else
-	e = interpretAssignCommon(istate, &Min, 1);
-#if LOG
-    if (e == EXP_CANT_INTERPRET)
-	printf("PostExp::interpret() CANT\n");
-#endif
-    return e;
-}
-
-Expression *AndAndExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("AndAndExp::interpret() %s\n", toChars());
-#endif
-    Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
-    {
-	if (e->isBool(FALSE))
-	    e = new IntegerExp(e1->loc, 0, type);
-	else if (e->isBool(TRUE))
-	{
-	    e = e2->interpret(istate);
-	    if (e != EXP_CANT_INTERPRET)
-	    {
-		if (e->isBool(FALSE))
-		    e = new IntegerExp(e1->loc, 0, type);
-		else if (e->isBool(TRUE))
-		    e = new IntegerExp(e1->loc, 1, type);
-		else
-		    e = EXP_CANT_INTERPRET;
-	    }
-	}
-	else
-	    e = EXP_CANT_INTERPRET;
-    }
-    return e;
-}
-
-Expression *OrOrExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("OrOrExp::interpret() %s\n", toChars());
-#endif
-    Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
-    {
-	if (e->isBool(TRUE))
-	    e = new IntegerExp(e1->loc, 1, type);
-	else if (e->isBool(FALSE))
-	{
-	    e = e2->interpret(istate);
-	    if (e != EXP_CANT_INTERPRET)
-	    {
-		if (e->isBool(FALSE))
-		    e = new IntegerExp(e1->loc, 0, type);
-		else if (e->isBool(TRUE))
-		    e = new IntegerExp(e1->loc, 1, type);
-		else
-		    e = EXP_CANT_INTERPRET;
-	    }
-	}
-	else
-	    e = EXP_CANT_INTERPRET;
-    }
-    return e;
-}
-
-
-Expression *CallExp::interpret(InterState *istate)
-{   Expression *e = EXP_CANT_INTERPRET;
-
-#if LOG
-    printf("CallExp::interpret() %s\n", toChars());
-#endif
-    if (e1->op == TOKvar)
-    {
-	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
-	if (fd)
-	{
-#if DMDV2
-	    enum BUILTIN b = fd->isBuiltin();
-	    if (b)
-	    {	Expressions args;
-		args.setDim(arguments->dim);
-		for (size_t i = 0; i < args.dim; i++)
-		{
-		    Expression *earg = (Expression *)arguments->data[i];
-		    earg = earg->interpret(istate);
-		    if (earg == EXP_CANT_INTERPRET)
-			return earg;
-		    args.data[i] = (void *)earg;
-		}
-		e = eval_builtin(b, &args);
-		if (!e)
-		    e = EXP_CANT_INTERPRET;
-	    }
-	    else
-#endif
-	    // Inline .dup
-	    if (fd->ident == Id::adDup && arguments && arguments->dim == 2)
-	    {
-		e = (Expression *)arguments->data[1];
-		e = e->interpret(istate);
-		if (e != EXP_CANT_INTERPRET)
-		{
-		    e = expType(type, e);
-		}
-	    }
-	    else
-	    {
-		Expression *eresult = fd->interpret(istate, arguments);
-		if (eresult)
-		    e = eresult;
-		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
-		    e = EXP_VOID_INTERPRET;
-		else
-		    error("cannot evaluate %s at compile time", toChars());
-	    }
-	}
-    }
-    return e;
-}
-
-Expression *CommaExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("CommaExp::interpret() %s\n", toChars());
-#endif
-    Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
-	e = e2->interpret(istate);
-    return e;
-}
-
-Expression *CondExp::interpret(InterState *istate)
-{
-#if LOG
-    printf("CondExp::interpret() %s\n", toChars());
-#endif
-    Expression *e = econd->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
-    {
-	if (e->isBool(TRUE))
-	    e = e1->interpret(istate);
-	else if (e->isBool(FALSE))
-	    e = e2->interpret(istate);
-	else
-	    e = EXP_CANT_INTERPRET;
-    }
-    return e;
-}
-
-Expression *ArrayLengthExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-
-#if LOG
-    printf("ArrayLengthExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
-    {
-	e = ArrayLength(type, e1);
-    }
-    else if (e1->op == TOKnull)
-    {
-	e = new IntegerExp(loc, 0, type);
-    }
-    else
-	goto Lcant;
-    return e;
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-Expression *IndexExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-    Expression *e2;
-
-#if LOG
-    printf("IndexExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-
-    if (e1->op == TOKstring || e1->op == TOKarrayliteral)
-    {
-	/* Set the $ variable
-	 */
-	e = ArrayLength(Type::tsize_t, e1);
-	if (e == EXP_CANT_INTERPRET)
-	    goto Lcant;
-	if (lengthVar)
-	    lengthVar->value = e;
-    }
-
-    e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    return Index(type, e1, e2);
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-
-Expression *SliceExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-    Expression *lwr;
-    Expression *upr;
-
-#if LOG
-    printf("SliceExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (!this->lwr)
-    {
-	e = e1->castTo(NULL, type);
-	return e->interpret(istate);
-    }
-
-    /* Set the $ variable
-     */
-    e = ArrayLength(Type::tsize_t, e1);
-    if (e == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (lengthVar)
-	lengthVar->value = e;
-
-    /* Evaluate lower and upper bounds of slice
-     */
-    lwr = this->lwr->interpret(istate);
-    if (lwr == EXP_CANT_INTERPRET)
-	goto Lcant;
-    upr = this->upr->interpret(istate);
-    if (upr == EXP_CANT_INTERPRET)
-	goto Lcant;
-
-    return Slice(type, e1, lwr, upr);
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-
-Expression *CatExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-    Expression *e2;
-
-#if LOG
-    printf("CatExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-    {
-	goto Lcant;
-    }
-    e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    return Cat(type, e1, e2);
-
-Lcant:
-#if LOG
-    printf("CatExp::interpret() %s CANT\n", toChars());
-#endif
-    return EXP_CANT_INTERPRET;
-}
-
-
-Expression *CastExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-
-#if LOG
-    printf("CastExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    return Cast(type, to, e1);
-
-Lcant:
-#if LOG
-    printf("CastExp::interpret() %s CANT\n", toChars());
-#endif
-    return EXP_CANT_INTERPRET;
-}
-
-
-Expression *AssertExp::interpret(InterState *istate)
-{   Expression *e;
-    Expression *e1;
-
-#if LOG
-    printf("AssertExp::interpret() %s\n", toChars());
-#endif
-    e1 = this->e1->interpret(istate);
-    if (e1 == EXP_CANT_INTERPRET)
-	goto Lcant;
-    if (e1->isBool(TRUE))
-    {
-    }
-    else if (e1->isBool(FALSE))
-    {
-	if (msg)
-	{
-	    e = msg->interpret(istate);
-	    if (e == EXP_CANT_INTERPRET)
-		goto Lcant;
-	    error("%s", e->toChars());
-	}
-	else
-	    error("%s failed", toChars());
-	goto Lcant;
-    }
-    else
-	goto Lcant;
-    return e1;
-
-Lcant:
-    return EXP_CANT_INTERPRET;
-}
-
-Expression *PtrExp::interpret(InterState *istate)
-{   Expression *e = EXP_CANT_INTERPRET;
-
-#if LOG
-    printf("PtrExp::interpret() %s\n", toChars());
-#endif
-
-    // Constant fold *(&structliteral + offset)
-    if (e1->op == TOKadd)
-    {	AddExp *ae = (AddExp *)e1;
-	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
-	{   AddrExp *ade = (AddrExp *)ae->e1;
-	    Expression *ex = ade->e1;
-	    ex = ex->interpret(istate);
-	    if (ex != EXP_CANT_INTERPRET)
-	    {
-		if (ex->op == TOKstructliteral)
-		{   StructLiteralExp *se = (StructLiteralExp *)ex;
-		    unsigned offset = ae->e2->toInteger();
-		    e = se->getField(type, offset);
-		    if (!e)
-			e = EXP_CANT_INTERPRET;
-		    return e;
-		}
-	    }
-	}
-	e = Ptr(type, e1);
-    }
-    else if (e1->op == TOKsymoff)
-    {	SymOffExp *soe = (SymOffExp *)e1;
-	VarDeclaration *v = soe->var->isVarDeclaration();
-	if (v)
-	{   Expression *ev = getVarExp(loc, istate, v);
-	    if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
-	    {	StructLiteralExp *se = (StructLiteralExp *)ev;
-		e = se->getField(type, soe->offset);
-		if (!e)
-		    e = EXP_CANT_INTERPRET;
-	    }
-	}
-    }
-#if LOG
-    if (e == EXP_CANT_INTERPRET)
-	printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
-#endif
-    return e;
-}
-
-Expression *DotVarExp::interpret(InterState *istate)
-{   Expression *e = EXP_CANT_INTERPRET;
-
-    Expression *ex = e1->interpret(istate);
-
-    // Constant fold structliteral.member
-    if (ex != EXP_CANT_INTERPRET && ex->op == TOKstructliteral)
-    {	StructLiteralExp *se = (StructLiteralExp *)ex;
-
-	VarDeclaration* v;
-	if (v = var->isVarDeclaration())
-	{
-	    e = se->getField(type, v->offset);
-	    if (!e)
-		e = EXP_CANT_INTERPRET;
-	}
-    }
-
-    return e;
-}
-
-/******************************* Special Functions ***************************/
-
-Expression *interpret_aaLen(InterState *istate, Expressions *arguments)
-{
-    if (!arguments || arguments->dim != 1)
-	return NULL;
-    Expression *earg = (Expression *)arguments->data[0];
-    earg = earg->interpret(istate);
-    if (earg == EXP_CANT_INTERPRET)
-	return NULL;
-    if (earg->op != TOKassocarrayliteral)
-	return NULL;
-    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
-    Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t);
-    return e;
-}
-
-Expression *interpret_aaKeys(InterState *istate, Expressions *arguments)
-{
-    //printf("interpret_aaKeys()\n");
-    if (!arguments || arguments->dim != 2)
-	return NULL;
-    Expression *earg = (Expression *)arguments->data[0];
-    earg = earg->interpret(istate);
-    if (earg == EXP_CANT_INTERPRET)
-	return NULL;
-    if (earg->op != TOKassocarrayliteral)
-	return NULL;
-    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
-    Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
-    return e;
-}
-
-Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
-{
-    //printf("interpret_aaValues()\n");
-    if (!arguments || arguments->dim != 3)
-	return NULL;
-    Expression *earg = (Expression *)arguments->data[0];
-    earg = earg->interpret(istate);
-    if (earg == EXP_CANT_INTERPRET)
-	return NULL;
-    if (earg->op != TOKassocarrayliteral)
-	return NULL;
-    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
-    Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
-    //printf("result is %s\n", e->toChars());
-    return e;
-}
-
+
+// 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 "mem.h"
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "mtype.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+
+#define LOG	0
+
+struct InterState
+{
+    InterState *caller;		// calling function's InterState
+    FuncDeclaration *fd;	// function being interpreted
+    Dsymbols vars;		// variables used in this function
+    Statement *start;		// if !=NULL, start execution at this statement
+    Statement *gotoTarget;	// target of EXP_GOTO_INTERPRET result
+
+    InterState();
+};
+
+InterState::InterState()
+{
+    memset(this, 0, sizeof(InterState));
+}
+
+Expression *interpret_aaLen(InterState *istate, Expressions *arguments);
+Expression *interpret_aaKeys(InterState *istate, Expressions *arguments);
+Expression *interpret_aaValues(InterState *istate, Expressions *arguments);
+
+/*************************************
+ * Attempt to interpret a function given the arguments.
+ * Input:
+ *	istate	state for calling function (NULL if none)
+ * Return result expression if successful, NULL if not.
+ */
+
+Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments)
+{
+#if LOG
+    printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars());
+    printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun);
+#endif
+    if (global.errors)
+	return NULL;
+    if (ident == Id::aaLen)
+	return interpret_aaLen(istate, arguments);
+    else if (ident == Id::aaKeys)
+	return interpret_aaKeys(istate, arguments);
+    else if (ident == Id::aaValues)
+	return interpret_aaValues(istate, arguments);
+
+    if (cantInterpret || semanticRun == 1)
+	return NULL;
+
+    if (needThis() || isNested() || !fbody)
+    {	cantInterpret = 1;
+	return NULL;
+    }
+
+    if (semanticRun == 0 && scope)
+    {
+	semantic3(scope);
+    if (global.errors)  // if errors compiling this function
+        return NULL;
+    }
+    if (semanticRun < 2)
+	return NULL;
+
+    Type *tb = type->toBasetype();
+    assert(tb->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)tb;
+    Type *tret = tf->next->toBasetype();
+    if (tf->varargs /*|| tret->ty == Tvoid*/)
+    {	cantInterpret = 1;
+	return NULL;
+    }
+
+    if (tf->parameters)
+    {	size_t dim = Argument::dim(tf->parameters);
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg = Argument::getNth(tf->parameters, i);
+	    if (arg->storageClass & STClazy)
+	    {   cantInterpret = 1;
+		return NULL;
+	    }
+	}
+    }
+
+    InterState istatex;
+    istatex.caller = istate;
+    istatex.fd = this;
+
+    Expressions vsave;		// place to save previous parameter values
+    size_t dim = 0;
+    if (arguments)
+    {
+	dim = arguments->dim;
+	assert(!dim || parameters->dim == dim);
+	vsave.setDim(dim);
+
+	/* Evaluate all the arguments to the function,
+	 * store the results in eargs[]
+	 */
+	Expressions eargs;
+	eargs.setDim(dim);
+
+	for (size_t i = 0; i < dim; i++)
+	{   Expression *earg = (Expression *)arguments->data[i];
+	    Argument *arg = Argument::getNth(tf->parameters, i);
+
+	    if (arg->storageClass & (STCout | STCref))
+	    {
+	    }
+	    else
+	    {	/* Value parameters
+		 */
+		Type *ta = arg->type->toBasetype();
+		if (ta->ty == Tsarray && earg->op == TOKaddress)
+		{
+		    /* Static arrays are passed by a simple pointer.
+		     * Skip past this to get at the actual arg.
+		     */
+		    earg = ((AddrExp *)earg)->e1;
+		}
+		earg = earg->interpret(istate ? istate : &istatex);
+		if (earg == EXP_CANT_INTERPRET)
+		    return NULL;
+	    }
+	    eargs.data[i] = earg;
+	}
+
+	for (size_t i = 0; i < dim; i++)
+	{   Expression *earg = (Expression *)eargs.data[i];
+	    Argument *arg = Argument::getNth(tf->parameters, i);
+	    VarDeclaration *v = (VarDeclaration *)parameters->data[i];
+	    vsave.data[i] = v->value;
+#if LOG
+	    printf("arg[%d] = %s\n", i, earg->toChars());
+#endif
+	    if (arg->storageClass & (STCout | STCref))
+	    {
+		/* Bind out or ref parameter to the corresponding
+		 * variable v2
+		 */
+		if (!istate || earg->op != TOKvar)
+		    return NULL;	// can't bind to non-interpreted vars
+
+		VarDeclaration *v2;
+		while (1)
+		{
+		    VarExp *ve = (VarExp *)earg;
+		    v2 = ve->var->isVarDeclaration();
+		    if (!v2)
+			return NULL;
+		    if (!v2->value || v2->value->op != TOKvar)
+			break;
+		    earg = v2->value;
+		}
+
+		v->value = new VarExp(earg->loc, v2);
+
+		/* Don't restore the value of v2 upon function return
+		 */
+		assert(istate);
+		for (size_t i = 0; i < istate->vars.dim; i++)
+		{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+		    if (v == v2)
+		    {	istate->vars.data[i] = NULL;
+			break;
+		    }
+		}
+	    }
+	    else
+	    {	/* Value parameters
+		 */
+		v->value = earg;
+	    }
+#if LOG
+	    printf("interpreted arg[%d] = %s\n", i, earg->toChars());
+#endif
+	}
+    }
+
+    /* Save the values of the local variables used
+     */
+    Expressions valueSaves;
+    if (istate)
+    {
+	//printf("saving local variables...\n");
+	valueSaves.setDim(istate->vars.dim);
+	for (size_t i = 0; i < istate->vars.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+	    if (v)
+	    {
+		//printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
+		valueSaves.data[i] = v->value;
+		v->value = NULL;
+	    }
+	}
+    }
+
+    Expression *e = NULL;
+
+    while (1)
+    {
+	e = fbody->interpret(&istatex);
+	if (e == EXP_CANT_INTERPRET)
+	{
+#if LOG
+	    printf("function body failed to interpret\n");
+#endif
+	    e = NULL;
+	}
+
+	/* This is how we deal with a recursive statement AST
+	 * that has arbitrary goto statements in it.
+	 * Bubble up a 'result' which is the target of the goto
+	 * statement, then go recursively down the AST looking
+	 * for that statement, then execute starting there.
+	 */
+	if (e == EXP_GOTO_INTERPRET)
+	{
+	    istatex.start = istatex.gotoTarget;	// set starting statement
+	    istatex.gotoTarget = NULL;
+	}
+	else
+	    break;
+    }
+
+    /* Restore the parameter values
+     */
+    for (size_t i = 0; i < dim; i++)
+    {
+	VarDeclaration *v = (VarDeclaration *)parameters->data[i];
+	v->value = (Expression *)vsave.data[i];
+    }
+
+    if (istate)
+    {
+	/* Restore the variable values
+	 */
+	//printf("restoring local variables...\n");
+	for (size_t i = 0; i < istate->vars.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+	    if (v)
+	    {	v->value = (Expression *)valueSaves.data[i];
+		//printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
+	    }
+	}
+    }
+
+    return e;
+}
+
+/******************************** Statement ***************************/
+
+#define START()				\
+    if (istate->start)			\
+    {	if (istate->start != this)	\
+	    return NULL;		\
+	istate->start = NULL;		\
+    }
+
+/***********************************
+ * Interpret the statement.
+ * Returns:
+ *	NULL	continue to next statement
+ *	EXP_CANT_INTERPRET	cannot interpret statement at compile time
+ *	!NULL	expression from return statement
+ */
+
+Expression *Statement::interpret(InterState *istate)
+{
+#if LOG
+    printf("Statement::interpret()\n");
+#endif
+    START()
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *ExpStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : "");
+#endif
+    START()
+    if (exp)
+    {
+	Expression *e = exp->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	{
+	    //printf("-ExpStatement::interpret(): %p\n", e);
+	    return EXP_CANT_INTERPRET;
+	}
+    }
+    return NULL;
+}
+
+Expression *CompoundStatement::interpret(InterState *istate)
+{   Expression *e = NULL;
+
+#if LOG
+    printf("CompoundStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statements)
+    {
+	for (size_t i = 0; i < statements->dim; i++)
+	{   Statement *s = (Statement *)statements->data[i];
+
+	    if (s)
+	    {
+		e = s->interpret(istate);
+		if (e)
+		    break;
+	    }
+	}
+    }
+#if LOG
+    printf("-CompoundStatement::interpret() %p\n", e);
+#endif
+    return e;
+}
+
+Expression *UnrolledLoopStatement::interpret(InterState *istate)
+{   Expression *e = NULL;
+
+#if LOG
+    printf("UnrolledLoopStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statements)
+    {
+	for (size_t i = 0; i < statements->dim; i++)
+	{   Statement *s = (Statement *)statements->data[i];
+
+	    e = s->interpret(istate);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_CONTINUE_INTERPRET)
+	    {	e = NULL;
+		continue;
+	    }
+	    if (e == EXP_BREAK_INTERPRET)
+	    {	e = NULL;
+		break;
+	    }
+	    if (e)
+		break;
+	}
+    }
+    return e;
+}
+
+Expression *IfStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("IfStatement::interpret(%s)\n", condition->toChars());
+#endif
+
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+    {
+	Expression *e = NULL;
+	if (ifbody)
+	    e = ifbody->interpret(istate);
+	if (istate->start && elsebody)
+	    e = elsebody->interpret(istate);
+	return e;
+    }
+
+    Expression *e = condition->interpret(istate);
+    assert(e);
+    //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n");
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(TRUE))
+	    e = ifbody ? ifbody->interpret(istate) : NULL;
+	else if (e->isBool(FALSE))
+	    e = elsebody ? elsebody->interpret(istate) : NULL;
+	else
+	{
+	    e = EXP_CANT_INTERPRET;
+	}
+    }
+    return e;
+}
+
+Expression *ScopeStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ScopeStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    return statement ? statement->interpret(istate) : NULL;
+}
+
+Expression *ReturnStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : "");
+#endif
+    START()
+    if (!exp)
+	return EXP_VOID_INTERPRET;
+#if LOG
+    Expression *e = exp->interpret(istate);
+    printf("e = %p\n", e);
+    return e;
+#else
+    return exp->interpret(istate);
+#endif
+}
+
+Expression *BreakStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("BreakStatement::interpret()\n");
+#endif
+    START()
+    if (ident)
+	return EXP_CANT_INTERPRET;
+    else
+	return EXP_BREAK_INTERPRET;
+}
+
+Expression *ContinueStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ContinueStatement::interpret()\n");
+#endif
+    START()
+    if (ident)
+	return EXP_CANT_INTERPRET;
+    else
+	return EXP_CONTINUE_INTERPRET;
+}
+
+Expression *WhileStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("WhileStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e != EXP_CONTINUE_INTERPRET)
+	    return e;
+    }
+
+    while (1)
+    {
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{   e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_CONTINUE_INTERPRET)
+		continue;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {	e = NULL;
+		break;
+	    }
+	    if (e)
+		break;
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *DoStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("DoStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e == EXP_CONTINUE_INTERPRET)
+	    goto Lcontinue;
+	if (e)
+	    return e;
+    }
+
+    while (1)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (e == EXP_BREAK_INTERPRET)
+	{   e = NULL;
+	    break;
+	}
+	if (e && e != EXP_CONTINUE_INTERPRET)
+	    break;
+
+    Lcontinue:
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *ForStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (init)
+    {
+	e = init->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	assert(!e);
+    }
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e == EXP_CONTINUE_INTERPRET)
+	    goto Lcontinue;
+	if (e)
+	    return e;
+    }
+
+    while (1)
+    {
+	if (!condition)
+	    goto Lhead;
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{
+	Lhead:
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e && e != EXP_CONTINUE_INTERPRET)
+		break;
+	Lcontinue:
+	    if (increment)
+	    {
+		e = increment->interpret(istate);
+		if (e == EXP_CANT_INTERPRET)
+		    break;
+	    }
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *ForeachStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForeachStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+	return NULL;
+
+    Expression *e = NULL;
+    Expression *eaggr;
+
+    if (value->isOut() || value->isRef())
+	return EXP_CANT_INTERPRET;
+
+    eaggr = aggr->interpret(istate);
+    if (eaggr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *dim = ArrayLength(Type::tsize_t, eaggr);
+    if (dim == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *keysave = key ? key->value : NULL;
+    Expression *valuesave = value->value;
+
+    uinteger_t d = dim->toUInteger();
+    uinteger_t index;
+
+    if (op == TOKforeach)
+    {
+	for (index = 0; index < d; index++)
+	{
+	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
+	    if (key)
+		key->value = ekey;
+	    e = Index(value->type, eaggr, ekey);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    value->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e == EXP_CONTINUE_INTERPRET)
+		e = NULL;
+	    else if (e)
+		break;
+	}
+    }
+    else // TOKforeach_reverse
+    {
+	for (index = d; index-- != 0;)
+	{
+	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
+	    if (key)
+		key->value = ekey;
+	    e = Index(value->type, eaggr, ekey);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    value->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e == EXP_CONTINUE_INTERPRET)
+		e = NULL;
+	    else if (e)
+		break;
+	}
+    }
+    value->value = valuesave;
+    if (key)
+	key->value = keysave;
+    return e;
+}
+
+#if DMDV2
+Expression *ForeachRangeStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForeachRangeStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+	return NULL;
+
+    Expression *e = NULL;
+    Expression *elwr = lwr->interpret(istate);
+    if (elwr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *eupr = upr->interpret(istate);
+    if (eupr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *keysave = key->value;
+
+    if (op == TOKforeach)
+    {
+	key->value = elwr;
+
+	while (1)
+	{
+	    e = Cmp(TOKlt, key->value->type, key->value, upr);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e->isBool(TRUE) == FALSE)
+	    {	e = NULL;
+		break;
+	    }
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    key->value = e;
+	}
+    }
+    else // TOKforeach_reverse
+    {
+	key->value = eupr;
+
+	while (1)
+	{
+	    e = Cmp(TOKgt, key->value->type, key->value, lwr);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e->isBool(TRUE) == FALSE)
+	    {	e = NULL;
+		break;
+	    }
+
+	    e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    key->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	}
+    }
+    key->value = keysave;
+    return e;
+}
+#endif
+
+Expression *SwitchStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("SwitchStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e = NULL;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	return e;
+    }
+
+
+    Expression *econdition = condition->interpret(istate);
+    if (econdition == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Statement *s = NULL;
+    if (cases)
+    {
+	for (size_t i = 0; i < cases->dim; i++)
+	{
+	    CaseStatement *cs = (CaseStatement *)cases->data[i];
+	    e = Equal(TOKequal, Type::tint32, econdition, cs->exp);
+	    if (e == EXP_CANT_INTERPRET)
+		return EXP_CANT_INTERPRET;
+	    if (e->isBool(TRUE))
+	    {	s = cs;
+		break;
+	    }
+	}
+    }
+    if (!s)
+    {	if (hasNoDefault)
+	    error("no default or case for %s in switch statement", econdition->toChars());
+	s = sdefault;
+    }
+
+    assert(s);
+    istate->start = s;
+    e = body ? body->interpret(istate) : NULL;
+    assert(!istate->start);
+    if (e == EXP_BREAK_INTERPRET)
+	return NULL;
+    return e;
+}
+
+Expression *CaseStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this);
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statement)
+	return statement->interpret(istate);
+    else
+	return NULL;
+}
+
+Expression *DefaultStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("DefaultStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statement)
+	return statement->interpret(istate);
+    else
+	return NULL;
+}
+
+Expression *GotoStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoStatement::interpret()\n");
+#endif
+    START()
+    assert(label && label->statement);
+    istate->gotoTarget = label->statement;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *GotoCaseStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoCaseStatement::interpret()\n");
+#endif
+    START()
+    assert(cs);
+    istate->gotoTarget = cs;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *GotoDefaultStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoDefaultStatement::interpret()\n");
+#endif
+    START()
+    assert(sw && sw->sdefault);
+    istate->gotoTarget = sw->sdefault;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *LabelStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("LabelStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    return statement ? statement->interpret(istate) : NULL;
+}
+
+/******************************** Expression ***************************/
+
+Expression *Expression::interpret(InterState *istate)
+{
+#if LOG
+    printf("Expression::interpret() %s\n", toChars());
+    printf("type = %s\n", type->toChars());
+    dump(0);
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *NullExp::interpret(InterState *istate)
+{
+    return this;
+}
+
+Expression *IntegerExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("IntegerExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *RealExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("RealExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *ComplexExp::interpret(InterState *istate)
+{
+    return this;
+}
+
+Expression *StringExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("StringExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *getVarExp(Loc loc, InterState *istate, Declaration *d)
+{
+    Expression *e = EXP_CANT_INTERPRET;
+    VarDeclaration *v = d->isVarDeclaration();
+    SymbolDeclaration *s = d->isSymbolDeclaration();
+    if (v)
+    {
+#if DMDV2
+	if ((v->isConst() || v->isInvariant()) && v->init && !v->value)
+#else
+	if (v->isConst() && v->init)
+#endif
+	{   e = v->init->toExpression();
+	    if (e && !e->type)
+		e->type = v->type;
+	}
+	else
+	{   e = v->value;
+	    if (!e)
+		error(loc, "variable %s is used before initialization", v->toChars());
+	    else if (e != EXP_CANT_INTERPRET)
+		e = e->interpret(istate);
+	}
+	if (!e)
+	    e = EXP_CANT_INTERPRET;
+    }
+    else if (s)
+    {
+	if (s->dsym->toInitializer() == s->sym)
+	{   Expressions *exps = new Expressions();
+	    e = new StructLiteralExp(0, s->dsym, exps);
+	    e = e->semantic(NULL);
+	}
+    }
+    return e;
+}
+
+Expression *VarExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("VarExp::interpret() %s\n", toChars());
+#endif
+    return getVarExp(loc, istate, var);
+}
+
+Expression *DeclarationExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("DeclarationExp::interpret() %s\n", toChars());
+#endif
+    Expression *e;
+    VarDeclaration *v = declaration->isVarDeclaration();
+    if (v)
+    {
+	Dsymbol *s = v->toAlias();
+	if (s == v && !v->isStatic() && v->init)
+	{
+	    ExpInitializer *ie = v->init->isExpInitializer();
+	    if (ie)
+		e = ie->exp->interpret(istate);
+	    else if (v->init->isVoidInitializer())
+		e = NULL;
+	}
+#if DMDV2
+	else if (s == v && (v->isConst() || v->isInvariant()) && v->init)
+#else
+	else if (s == v && v->isConst() && v->init)
+#endif
+	{   e = v->init->toExpression();
+	    if (!e)
+		e = EXP_CANT_INTERPRET;
+	    else if (!e->type)
+		e->type = v->type;
+	}
+    }
+    else if (declaration->isAttribDeclaration() ||
+	     declaration->isTemplateMixin() ||
+	     declaration->isTupleDeclaration())
+    {	// These can be made to work, too lazy now
+	e = EXP_CANT_INTERPRET;
+    }
+    else
+    {	// Others should not contain executable code, so are trivial to evaluate
+	e = NULL;
+    }
+#if LOG
+    printf("-DeclarationExp::interpret(): %p\n", e);
+#endif
+    return e;
+}
+
+Expression *TupleExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("TupleExp::interpret() %s\n", toChars());
+#endif
+    Expressions *expsx = NULL;
+
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+	Expression *ex;
+
+	ex = e->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	{   delete expsx;
+	    return ex;
+	}
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != e)
+	{
+	    if (!expsx)
+	    {	expsx = new Expressions();
+		expsx->setDim(exps->dim);
+		for (size_t j = 0; j < i; j++)
+		{
+		    expsx->data[j] = exps->data[j];
+		}
+	    }
+	    expsx->data[i] = (void *)ex;
+	}
+    }
+    if (expsx)
+    {	TupleExp *te = new TupleExp(loc, expsx);
+	expandTuples(te->exps);
+	te->type = new TypeTuple(te->exps);
+	return te;
+    }
+    return this;
+}
+
+Expression *ArrayLiteralExp::interpret(InterState *istate)
+{   Expressions *expsx = NULL;
+
+#if LOG
+    printf("ArrayLiteralExp::interpret() %s\n", toChars());
+#endif
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    Expression *ex;
+
+	    ex = e->interpret(istate);
+	    if (ex == EXP_CANT_INTERPRET)
+	    {   delete expsx;
+		return EXP_CANT_INTERPRET;
+	    }
+
+	    /* If any changes, do Copy On Write
+	     */
+	    if (ex != e)
+	    {
+		if (!expsx)
+		{   expsx = new Expressions();
+		    expsx->setDim(elements->dim);
+		    for (size_t j = 0; j < elements->dim; j++)
+		    {
+			expsx->data[j] = elements->data[j];
+		    }
+		}
+		expsx->data[i] = (void *)ex;
+	    }
+	}
+    }
+    if (elements && expsx)
+    {
+	expandTuples(expsx);
+	if (expsx->dim != elements->dim)
+	{   delete expsx;
+	    return EXP_CANT_INTERPRET;
+	}
+	ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx);
+	ae->type = type;
+	return ae;
+    }
+    return this;
+}
+
+Expression *AssocArrayLiteralExp::interpret(InterState *istate)
+{   Expressions *keysx = keys;
+    Expressions *valuesx = values;
+
+#if LOG
+    printf("AssocArrayLiteralExp::interpret() %s\n", toChars());
+#endif
+    for (size_t i = 0; i < keys->dim; i++)
+    {   Expression *ekey = (Expression *)keys->data[i];
+	Expression *evalue = (Expression *)values->data[i];
+	Expression *ex;
+
+	ex = ekey->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	    goto Lerr;
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != ekey)
+	{
+	    if (keysx == keys)
+		keysx = (Expressions *)keys->copy();
+	    keysx->data[i] = (void *)ex;
+	}
+
+	ex = evalue->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	    goto Lerr;
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != evalue)
+	{
+	    if (valuesx == values)
+		valuesx = (Expressions *)values->copy();
+	    valuesx->data[i] = (void *)ex;
+	}
+    }
+    if (keysx != keys)
+	expandTuples(keysx);
+    if (valuesx != values)
+	expandTuples(valuesx);
+    if (keysx->dim != valuesx->dim)
+	goto Lerr;
+
+    /* Remove duplicate keys
+     */
+    for (size_t i = 1; i < keysx->dim; i++)
+    {   Expression *ekey = (Expression *)keysx->data[i - 1];
+
+	for (size_t j = i; j < keysx->dim; j++)
+	{   Expression *ekey2 = (Expression *)keysx->data[j];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
+	    if (ex == EXP_CANT_INTERPRET)
+		goto Lerr;
+	    if (ex->isBool(TRUE))	// if a match
+	    {
+		// Remove ekey
+		if (keysx == keys)
+		    keysx = (Expressions *)keys->copy();
+		if (valuesx == values)
+		    valuesx = (Expressions *)values->copy();
+		keysx->remove(i - 1);
+		valuesx->remove(i - 1);
+		i -= 1;		// redo the i'th iteration
+		break;
+	    }
+	}
+    }
+
+    if (keysx != keys || valuesx != values)
+    {
+	AssocArrayLiteralExp *ae;
+	ae = new AssocArrayLiteralExp(loc, keysx, valuesx);
+	ae->type = type;
+	return ae;
+    }
+    return this;
+
+Lerr:
+    if (keysx != keys)
+	delete keysx;
+    if (valuesx != values)
+	delete values;
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *StructLiteralExp::interpret(InterState *istate)
+{   Expressions *expsx = NULL;
+
+#if LOG
+    printf("StructLiteralExp::interpret() %s\n", toChars());
+#endif
+    /* We don't know how to deal with overlapping fields
+     */
+    if (sd->hasUnions)
+	return EXP_CANT_INTERPRET;
+
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    if (!e)
+		continue;
+
+	    Expression *ex = e->interpret(istate);
+	    if (ex == EXP_CANT_INTERPRET)
+	    {   delete expsx;
+		return EXP_CANT_INTERPRET;
+	    }
+
+	    /* If any changes, do Copy On Write
+	     */
+	    if (ex != e)
+	    {
+		if (!expsx)
+		{   expsx = new Expressions();
+		    expsx->setDim(elements->dim);
+		    for (size_t j = 0; j < elements->dim; j++)
+		    {
+			expsx->data[j] = elements->data[j];
+		    }
+		}
+		expsx->data[i] = (void *)ex;
+	    }
+	}
+    }
+    if (elements && expsx)
+    {
+	expandTuples(expsx);
+	if (expsx->dim != elements->dim)
+	{   delete expsx;
+	    return EXP_CANT_INTERPRET;
+	}
+	StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx);
+	se->type = type;
+	return se;
+    }
+    return this;
+}
+
+Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *))
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("UnaExp::interpretCommon() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1)
+	goto Lcant;
+
+    e = (*fp)(type, e1);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define UNA_INTERPRET(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon(istate, &op);		\
+}
+
+UNA_INTERPRET(Neg)
+UNA_INTERPRET(Com)
+UNA_INTERPRET(Not)
+UNA_INTERPRET(Bool)
+
+
+typedef Expression *(*fp_t)(Type *, Expression *, Expression *);
+
+Expression *BinExp::interpretCommon(InterState *istate, fp_t fp)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("BinExp::interpretCommon() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1)
+	goto Lcant;
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e2->isConst() != 1)
+	goto Lcant;
+
+    e = (*fp)(type, e1, e2);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define BIN_INTERPRET(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon(istate, &op);		\
+}
+
+BIN_INTERPRET(Add)
+BIN_INTERPRET(Min)
+BIN_INTERPRET(Mul)
+BIN_INTERPRET(Div)
+BIN_INTERPRET(Mod)
+BIN_INTERPRET(Shl)
+BIN_INTERPRET(Shr)
+BIN_INTERPRET(Ushr)
+BIN_INTERPRET(And)
+BIN_INTERPRET(Or)
+BIN_INTERPRET(Xor)
+
+
+typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);
+
+Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("BinExp::interpretCommon2() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1 &&
+	e1->op != TOKnull &&
+	e1->op != TOKstring &&
+	e1->op != TOKarrayliteral &&
+	e1->op != TOKstructliteral)
+	goto Lcant;
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e2->isConst() != 1 &&
+	e2->op != TOKnull &&
+	e2->op != TOKstring &&
+	e2->op != TOKarrayliteral &&
+	e2->op != TOKstructliteral)
+	goto Lcant;
+
+    e = (*fp)(op, type, e1, e2);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define BIN_INTERPRET2(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon2(istate, &op);		\
+}
+
+BIN_INTERPRET2(Equal)
+BIN_INTERPRET2(Identity)
+BIN_INTERPRET2(Cmp)
+
+Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
+{
+#if LOG
+    printf("BinExp::interpretAssignCommon() %s\n", toChars());
+#endif
+    Expression *e = EXP_CANT_INTERPRET;
+    Expression *e1 = this->e1;
+
+    if (fp)
+    {
+	if (e1->op == TOKcast)
+	{   CastExp *ce = (CastExp *)e1;
+	    e1 = ce->e1;
+	}
+    }
+    if (e1 == EXP_CANT_INTERPRET)
+	return e1;
+    Expression *e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	return e2;
+
+    /* Assignment to variable of the form:
+     *	v = e2
+     */
+    if (e1->op == TOKvar)
+    {
+	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v && !v->isDataseg())
+	{
+	    /* Chase down rebinding of out and ref
+	     */
+	    if (v->value && v->value->op == TOKvar)
+	    {
+		VarExp *ve2 = (VarExp *)v->value;
+		if (ve2->var->isSymbolDeclaration())
+		{
+		    /* This can happen if v is a struct initialized to
+		     * 0 using an __initZ SymbolDeclaration from
+		     * TypeStruct::defaultInit()
+		     */
+		}
+		else
+		    v = ve2->var->isVarDeclaration();
+		assert(v);
+	    }
+
+	    Expression *ev = v->value;
+	    if (fp && !ev)
+	    {	error("variable %s is used before initialization", v->toChars());
+		return e;
+	    }
+	    if (fp)
+		e2 = (*fp)(v->type, ev, e2);
+	    else
+	    {	/* Look for special case of struct being initialized with 0.
+		 */
+		if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64)
+		{
+		    e2 = v->type->defaultInit();
+		}
+		e2 = Cast(v->type, v->type, e2);
+	    }
+	    if (e2 != EXP_CANT_INTERPRET)
+	    {
+		if (!v->isParameter())
+		{
+		    for (size_t i = 0; 1; i++)
+		    {
+			if (i == istate->vars.dim)
+			{   istate->vars.push(v);
+			    //printf("\tadding %s to istate\n", v->toChars());
+			    break;
+			}
+			if (v == (VarDeclaration *)istate->vars.data[i])
+			    break;
+		    }
+		}
+		v->value = e2;
+		e = Cast(type, type, post ? ev : e2);
+	    }
+	}
+    }
+    /* Assignment to struct member of the form:
+     *   v.var = e2
+     */
+    else if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)((DotVarExp *)e1)->e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+
+	if (v->isDataseg())
+	    return EXP_CANT_INTERPRET;
+	if (fp && !v->value)
+	{   error("variable %s is used before initialization", v->toChars());
+	    return e;
+	}
+	Expression *vie = v->value;
+	if (vie->op == TOKvar)
+	{
+	    Declaration *d = ((VarExp *)vie)->var;
+	    vie = getVarExp(e1->loc, istate, d);
+	}
+	if (vie->op != TOKstructliteral)
+	    return EXP_CANT_INTERPRET;
+	StructLiteralExp *se = (StructLiteralExp *)vie;
+	VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration();
+	if (!vf)
+	    return EXP_CANT_INTERPRET;
+	int fieldi = se->getFieldIndex(type, vf->offset);
+	if (fieldi == -1)
+	    return EXP_CANT_INTERPRET;
+	Expression *ev = se->getField(type, vf->offset);
+	if (fp)
+	    e2 = (*fp)(type, ev, e2);
+	else
+	    e2 = Cast(type, type, e2);
+	if (e2 == EXP_CANT_INTERPRET)
+	    return e2;
+
+	if (!v->isParameter())
+	{
+	    for (size_t i = 0; 1; i++)
+	    {
+		if (i == istate->vars.dim)
+		{   istate->vars.push(v);
+		    break;
+		}
+		if (v == (VarDeclaration *)istate->vars.data[i])
+		    break;
+	    }
+	}
+
+	/* Create new struct literal reflecting updated fieldi
+	 */
+	Expressions *expsx = new Expressions();
+	expsx->setDim(se->elements->dim);
+	for (size_t j = 0; j < expsx->dim; j++)
+	{
+	    if (j == fieldi)
+		expsx->data[j] = (void *)e2;
+	    else
+		expsx->data[j] = se->elements->data[j];
+	}
+	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
+	v->value->type = se->type;
+
+	e = Cast(type, type, post ? ev : e2);
+    }
+    /* Assignment to struct member of the form:
+     *   *(symoffexp) = e2
+     */
+    else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff)
+    {	SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
+	VarDeclaration *v = soe->var->isVarDeclaration();
+
+	if (v->isDataseg())
+	    return EXP_CANT_INTERPRET;
+	if (fp && !v->value)
+	{   error("variable %s is used before initialization", v->toChars());
+	    return e;
+	}
+	Expression *vie = v->value;
+	if (vie->op == TOKvar)
+	{
+	    Declaration *d = ((VarExp *)vie)->var;
+	    vie = getVarExp(e1->loc, istate, d);
+	}
+	if (vie->op != TOKstructliteral)
+	    return EXP_CANT_INTERPRET;
+	StructLiteralExp *se = (StructLiteralExp *)vie;
+	int fieldi = se->getFieldIndex(type, soe->offset);
+	if (fieldi == -1)
+	    return EXP_CANT_INTERPRET;
+	Expression *ev = se->getField(type, soe->offset);
+	if (fp)
+	    e2 = (*fp)(type, ev, e2);
+	else
+	    e2 = Cast(type, type, e2);
+	if (e2 == EXP_CANT_INTERPRET)
+	    return e2;
+
+	if (!v->isParameter())
+	{
+	    for (size_t i = 0; 1; i++)
+	    {
+		if (i == istate->vars.dim)
+		{   istate->vars.push(v);
+		    break;
+		}
+		if (v == (VarDeclaration *)istate->vars.data[i])
+		    break;
+	    }
+	}
+
+	/* Create new struct literal reflecting updated fieldi
+	 */
+	Expressions *expsx = new Expressions();
+	expsx->setDim(se->elements->dim);
+	for (size_t j = 0; j < expsx->dim; j++)
+	{
+	    if (j == fieldi)
+		expsx->data[j] = (void *)e2;
+	    else
+		expsx->data[j] = se->elements->data[j];
+	}
+	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
+	v->value->type = se->type;
+
+	e = Cast(type, type, post ? ev : e2);
+    }
+    /* Assignment to array element of the form:
+     *   a[i] = e2
+     */
+    else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar)
+    {	IndexExp *ie = (IndexExp *)e1;
+	VarExp *ve = (VarExp *)ie->e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+
+	if (!v || v->isDataseg())
+	    return EXP_CANT_INTERPRET;
+	if (!v->value)
+	{
+	    if (fp)
+	    {   error("variable %s is used before initialization", v->toChars());
+		return e;
+	    }
+
+	    Type *t = v->type->toBasetype();
+	    if (t->ty == Tsarray)
+	    {
+		/* This array was void initialized. Create a
+		 * default initializer for it.
+		 * What we should do is fill the array literal with
+		 * NULL data, so use-before-initialized can be detected.
+		 * But we're too lazy at the moment to do it, as that
+		 * involves redoing Index() and whoever calls it.
+		 */
+		Expression *ev = v->type->defaultInit();
+		size_t dim = ((TypeSArray *)t)->dim->toInteger();
+		Expressions *elements = new Expressions();
+		elements->setDim(dim);
+		for (size_t i = 0; i < dim; i++)
+		    elements->data[i] = (void *)ev;
+		ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
+		ae->type = v->type;
+		v->value = ae;
+	    }
+	    else
+		return EXP_CANT_INTERPRET;
+	}
+
+	ArrayLiteralExp *ae = NULL;
+	AssocArrayLiteralExp *aae = NULL;
+	StringExp *se = NULL;
+	if (v->value->op == TOKarrayliteral)
+	    ae = (ArrayLiteralExp *)v->value;
+	else if (v->value->op == TOKassocarrayliteral)
+	    aae = (AssocArrayLiteralExp *)v->value;
+	else if (v->value->op == TOKstring)
+	    se = (StringExp *)v->value;
+	else
+	    return EXP_CANT_INTERPRET;
+
+	Expression *index = ie->e2->interpret(istate);
+	if (index == EXP_CANT_INTERPRET)
+	    return EXP_CANT_INTERPRET;
+	Expression *ev;
+	if (fp || ae || se)	// not for aae, because key might not be there
+	{
+	    ev = Index(type, v->value, index);
+	    if (ev == EXP_CANT_INTERPRET)
+		return EXP_CANT_INTERPRET;
+	}
+
+	if (fp)
+	    e2 = (*fp)(type, ev, e2);
+	else
+	    e2 = Cast(type, type, e2);
+	if (e2 == EXP_CANT_INTERPRET)
+	    return e2;
+
+	if (!v->isParameter())
+	{
+	    for (size_t i = 0; 1; i++)
+	    {
+		if (i == istate->vars.dim)
+		{   istate->vars.push(v);
+		    break;
+		}
+		if (v == (VarDeclaration *)istate->vars.data[i])
+		    break;
+	    }
+	}
+
+	if (ae)
+	{
+	    /* Create new array literal reflecting updated elem
+	     */
+	    int elemi = index->toInteger();
+	    Expressions *expsx = new Expressions();
+	    expsx->setDim(ae->elements->dim);
+	    for (size_t j = 0; j < expsx->dim; j++)
+	    {
+		if (j == elemi)
+		    expsx->data[j] = (void *)e2;
+		else
+		    expsx->data[j] = ae->elements->data[j];
+	    }
+	    v->value = new ArrayLiteralExp(ae->loc, expsx);
+	    v->value->type = ae->type;
+	}
+	else if (aae)
+	{
+	    /* Create new associative array literal reflecting updated key/value
+	     */
+	    Expressions *keysx = aae->keys;
+	    Expressions *valuesx = new Expressions();
+	    valuesx->setDim(aae->values->dim);
+	    int updated = 0;
+	    for (size_t j = valuesx->dim; j; )
+	    {	j--;
+		Expression *ekey = (Expression *)aae->keys->data[j];
+		Expression *ex = Equal(TOKequal, Type::tbool, ekey, index);
+		if (ex == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		if (ex->isBool(TRUE))
+		{   valuesx->data[j] = (void *)e2;
+		    updated = 1;
+		}
+		else
+		    valuesx->data[j] = aae->values->data[j];
+	    }
+	    if (!updated)
+	    {	// Append index/e2 to keysx[]/valuesx[]
+		valuesx->push(e2);
+		keysx = (Expressions *)keysx->copy();
+		keysx->push(index);
+	    }
+	    v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx);
+	    v->value->type = aae->type;
+	}
+	else if (se)
+	{
+	    /* Create new string literal reflecting updated elem
+	     */
+	    int elemi = index->toInteger();
+	    unsigned char *s;
+	    s = (unsigned char *)mem.calloc(se->len + 1, se->sz);
+	    memcpy(s, se->string, se->len * se->sz);
+	    unsigned value = e2->toInteger();
+	    switch (se->sz)
+	    {
+		case 1:	s[elemi] = value; break;
+		case 2:	((unsigned short *)s)[elemi] = value; break;
+		case 4:	((unsigned *)s)[elemi] = value; break;
+		default:
+		    assert(0);
+		    break;
+	    }
+	    StringExp *se2 = new StringExp(se->loc, s, se->len);
+	    se2->committed = se->committed;
+	    se2->postfix = se->postfix;
+	    se2->type = se->type;
+	    v->value = se2;
+	}
+	else
+	    assert(0);
+
+	e = Cast(type, type, post ? ev : e2);
+    }
+    else
+    {
+#ifdef DEBUG
+	dump(0);
+#endif
+    }
+    return e;
+}
+
+Expression *AssignExp::interpret(InterState *istate)
+{
+    return interpretAssignCommon(istate, NULL);
+}
+
+#define BIN_ASSIGN_INTERPRET(op) \
+Expression *op##AssignExp::interpret(InterState *istate)	\
+{								\
+    return interpretAssignCommon(istate, &op);			\
+}
+
+BIN_ASSIGN_INTERPRET(Add)
+BIN_ASSIGN_INTERPRET(Min)
+BIN_ASSIGN_INTERPRET(Cat)
+BIN_ASSIGN_INTERPRET(Mul)
+BIN_ASSIGN_INTERPRET(Div)
+BIN_ASSIGN_INTERPRET(Mod)
+BIN_ASSIGN_INTERPRET(Shl)
+BIN_ASSIGN_INTERPRET(Shr)
+BIN_ASSIGN_INTERPRET(Ushr)
+BIN_ASSIGN_INTERPRET(And)
+BIN_ASSIGN_INTERPRET(Or)
+BIN_ASSIGN_INTERPRET(Xor)
+
+Expression *PostExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("PostExp::interpret() %s\n", toChars());
+#endif
+    Expression *e;
+    if (op == TOKplusplus)
+	e = interpretAssignCommon(istate, &Add, 1);
+    else
+	e = interpretAssignCommon(istate, &Min, 1);
+#if LOG
+    if (e == EXP_CANT_INTERPRET)
+	printf("PostExp::interpret() CANT\n");
+#endif
+    return e;
+}
+
+Expression *AndAndExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("AndAndExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(FALSE))
+	    e = new IntegerExp(e1->loc, 0, type);
+	else if (e->isBool(TRUE))
+	{
+	    e = e2->interpret(istate);
+	    if (e != EXP_CANT_INTERPRET)
+	    {
+		if (e->isBool(FALSE))
+		    e = new IntegerExp(e1->loc, 0, type);
+		else if (e->isBool(TRUE))
+		    e = new IntegerExp(e1->loc, 1, type);
+		else
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+Expression *OrOrExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("OrOrExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(TRUE))
+	    e = new IntegerExp(e1->loc, 1, type);
+	else if (e->isBool(FALSE))
+	{
+	    e = e2->interpret(istate);
+	    if (e != EXP_CANT_INTERPRET)
+	    {
+		if (e->isBool(FALSE))
+		    e = new IntegerExp(e1->loc, 0, type);
+		else if (e->isBool(TRUE))
+		    e = new IntegerExp(e1->loc, 1, type);
+		else
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+
+Expression *CallExp::interpret(InterState *istate)
+{   Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+    printf("CallExp::interpret() %s\n", toChars());
+#endif
+    if (e1->op == TOKvar)
+    {
+	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
+	if (fd)
+	{
+#if DMDV2
+	    enum BUILTIN b = fd->isBuiltin();
+	    if (b)
+	    {	Expressions args;
+		args.setDim(arguments->dim);
+		for (size_t i = 0; i < args.dim; i++)
+		{
+		    Expression *earg = (Expression *)arguments->data[i];
+		    earg = earg->interpret(istate);
+		    if (earg == EXP_CANT_INTERPRET)
+			return earg;
+		    args.data[i] = (void *)earg;
+		}
+		e = eval_builtin(b, &args);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+	    }
+	    else
+#endif
+	    // Inline .dup
+	    if (fd->ident == Id::adDup && arguments && arguments->dim == 2)
+	    {
+		e = (Expression *)arguments->data[1];
+		e = e->interpret(istate);
+		if (e != EXP_CANT_INTERPRET)
+		{
+		    e = expType(type, e);
+		}
+	    }
+	    else
+	    {
+		Expression *eresult = fd->interpret(istate, arguments);
+		if (eresult)
+		    e = eresult;
+		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
+		    e = EXP_VOID_INTERPRET;
+		else
+		    error("cannot evaluate %s at compile time", toChars());
+	    }
+	}
+    }
+    return e;
+}
+
+Expression *CommaExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("CommaExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+	e = e2->interpret(istate);
+    return e;
+}
+
+Expression *CondExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("CondExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = econd->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(TRUE))
+	    e = e1->interpret(istate);
+	else if (e->isBool(FALSE))
+	    e = e2->interpret(istate);
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+Expression *ArrayLengthExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("ArrayLengthExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
+    {
+	e = ArrayLength(type, e1);
+    }
+    else if (e1->op == TOKnull)
+    {
+	e = new IntegerExp(loc, 0, type);
+    }
+    else
+	goto Lcant;
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *IndexExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("IndexExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral)
+    {
+	/* Set the $ variable
+	 */
+	e = ArrayLength(Type::tsize_t, e1);
+	if (e == EXP_CANT_INTERPRET)
+	    goto Lcant;
+	if (lengthVar)
+	    lengthVar->value = e;
+    }
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Index(type, e1, e2);
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *SliceExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *lwr;
+    Expression *upr;
+
+#if LOG
+    printf("SliceExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (!this->lwr)
+    {
+	e = e1->castTo(NULL, type);
+	return e->interpret(istate);
+    }
+
+    /* Set the $ variable
+     */
+    e = ArrayLength(Type::tsize_t, e1);
+    if (e == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (lengthVar)
+	lengthVar->value = e;
+
+    /* Evaluate lower and upper bounds of slice
+     */
+    lwr = this->lwr->interpret(istate);
+    if (lwr == EXP_CANT_INTERPRET)
+	goto Lcant;
+    upr = this->upr->interpret(istate);
+    if (upr == EXP_CANT_INTERPRET)
+	goto Lcant;
+
+    return Slice(type, e1, lwr, upr);
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *CatExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("CatExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+    {
+	goto Lcant;
+    }
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Cat(type, e1, e2);
+
+Lcant:
+#if LOG
+    printf("CatExp::interpret() %s CANT\n", toChars());
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *CastExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("CastExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Cast(type, to, e1);
+
+Lcant:
+#if LOG
+    printf("CastExp::interpret() %s CANT\n", toChars());
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *AssertExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("AssertExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isBool(TRUE))
+    {
+    }
+    else if (e1->isBool(FALSE))
+    {
+	if (msg)
+	{
+	    e = msg->interpret(istate);
+	    if (e == EXP_CANT_INTERPRET)
+		goto Lcant;
+	    error("%s", e->toChars());
+	}
+	else
+	    error("%s failed", toChars());
+	goto Lcant;
+    }
+    else
+	goto Lcant;
+    return e1;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *PtrExp::interpret(InterState *istate)
+{   Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+    printf("PtrExp::interpret() %s\n", toChars());
+#endif
+
+    // Constant fold *(&structliteral + offset)
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    Expression *ex = ade->e1;
+	    ex = ex->interpret(istate);
+	    if (ex != EXP_CANT_INTERPRET)
+	    {
+		if (ex->op == TOKstructliteral)
+		{   StructLiteralExp *se = (StructLiteralExp *)ex;
+		    unsigned offset = ae->e2->toInteger();
+		    e = se->getField(type, offset);
+		    if (!e)
+			e = EXP_CANT_INTERPRET;
+		    return e;
+		}
+	    }
+	}
+	e = Ptr(type, e1);
+    }
+    else if (e1->op == TOKsymoff)
+    {	SymOffExp *soe = (SymOffExp *)e1;
+	VarDeclaration *v = soe->var->isVarDeclaration();
+	if (v)
+	{   Expression *ev = getVarExp(loc, istate, v);
+	    if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ev;
+		e = se->getField(type, soe->offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+    }
+#if LOG
+    if (e == EXP_CANT_INTERPRET)
+	printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
+#endif
+    return e;
+}
+
+Expression *DotVarExp::interpret(InterState *istate)
+{   Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+    printf("DotVarExp::interpret() %s\n", toChars());
+#endif
+
+    Expression *ex = e1->interpret(istate);
+    if (ex != EXP_CANT_INTERPRET)
+    {
+	if (ex->op == TOKstructliteral)
+	{   StructLiteralExp *se = (StructLiteralExp *)ex;
+	    VarDeclaration *v = var->isVarDeclaration();
+	    if (v)
+	    {	e = se->getField(type, v->offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+
+#if LOG
+    if (e == EXP_CANT_INTERPRET)
+	printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
+#endif
+    return e;
+}
+
+/******************************* Special Functions ***************************/
+
+Expression *interpret_aaLen(InterState *istate, Expressions *arguments)
+{
+    if (!arguments || arguments->dim != 1)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t);
+    return e;
+}
+
+Expression *interpret_aaKeys(InterState *istate, Expressions *arguments)
+{
+    //printf("interpret_aaKeys()\n");
+    if (!arguments || arguments->dim != 2)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
+    return e;
+}
+
+Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
+{
+    //printf("interpret_aaValues()\n");
+    if (!arguments || arguments->dim != 3)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
+    //printf("result is %s\n", e->toChars());
+    return e;
+}
+
--- a/dmd/man.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/man.c	Tue Jan 06 16:33:51 2009 +0100
@@ -1,60 +1,60 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 2008-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 <stdlib.h>
-#include <assert.h>
-
-#if _WIN32
-
-#include <windows.h>
-
-#pragma comment(lib,"shell32.lib")
-
-void browse(const char *url)
-{
-    ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
-}
-
-#endif
-
-#if linux || __APPLE__
-
-#include	<sys/types.h>
-#include	<sys/wait.h>
-#include	<unistd.h>
-
-void browse(const char *url)
-{
-    pid_t childpid;
-    const char *args[3];
-
-    char *browser = getenv("BROWSER");
-    if (browser)
-	browser = strdup(browser);
-    else
-	browser = "firefox";
-
-    args[0] = browser;
-    args[1] = url;
-    args[2] = NULL;
-
-    childpid = fork();
-    if (childpid == 0)
-    {
-	execvp(args[0], (char**)args);
-	perror(args[0]);		// failed to execute
-	return;
-    }
-}
-
-#endif
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2008-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 <stdlib.h>
+#include <assert.h>
+
+#if _WIN32
+
+#include <windows.h>
+
+#pragma comment(lib,"shell32.lib")
+
+void browse(const char *url)
+{
+    ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
+}
+
+#endif
+
+#if linux || __APPLE__
+
+#include	<sys/types.h>
+#include	<sys/wait.h>
+#include	<unistd.h>
+
+void browse(const char *url)
+{
+    pid_t childpid;
+    const char *args[3];
+
+    const char *browser = getenv("BROWSER");
+    if (browser)
+	browser = strdup(browser);
+    else
+	browser = "firefox";
+
+    args[0] = browser;
+    args[1] = url;
+    args[2] = NULL;
+
+    childpid = fork();
+    if (childpid == 0)
+    {
+	execvp(args[0], (char**)args);
+	perror(args[0]);		// failed to execute
+	return;
+    }
+}
+
+#endif
+
--- a/dmd/mars.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/mars.c	Tue Jan 06 16:33:51 2009 +0100
@@ -63,7 +63,7 @@
 
     copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen";
     written = "written by Walter Bright and Tomas Lindquist Olsen";
-    version = "v1.037";
+    version = "v1.038";
     ldc_version = LDC_REV;
     llvm_version = LLVM_REV;
     global.structalign = 8;
--- a/dmd/module.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/module.c	Tue Jan 06 16:33:51 2009 +0100
@@ -889,6 +889,38 @@
     //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
 }
 
+/************************************
+ * Recursively look at every module this module imports,
+ * return TRUE if it imports m.
+ * Can be used to detect circular imports.
+ */
+
+int Module::imports(Module *m)
+{
+    //printf("%s Module::imports(%s)\n", toChars(), m->toChars());
+    int aimports_dim = aimports.dim;
+#if 0
+    for (int i = 0; i < aimports.dim; i++)
+    {	Module *mi = (Module *)aimports.data[i];
+	printf("\t[%d] %s\n", i, mi->toChars());
+    }
+#endif
+    for (int i = 0; i < aimports.dim; i++)
+    {	Module *mi = (Module *)aimports.data[i];
+	if (mi == m)
+	    return TRUE;
+	if (!mi->insearch)
+	{
+	    mi->insearch = 1;
+	    int r = mi->imports(m);
+	    mi->insearch = 0;
+	    if (r)
+		return r;
+	}
+    }
+    return FALSE;
+}
+
 /* =========================== ModuleDeclaration ===================== */
 
 ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id)
--- a/dmd/module.h	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/module.h	Tue Jan 06 16:33:51 2009 +0100
@@ -141,6 +141,7 @@
     void deleteObjFile();
     void addDeferredSemantic(Dsymbol *s);
     void runDeferredSemantic();
+    int imports(Module *m);
 
     // Back end
 
--- a/dmd/mtype.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/mtype.c	Tue Jan 06 16:33:51 2009 +0100
@@ -3721,6 +3721,34 @@
     return t;
 }
 
+Dsymbol *TypeInstance::toDsymbol(Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeInstance::semantic(%s)\n", toChars());
+
+    if (sc->parameterSpecialization)
+    {
+	unsigned errors = global.errors;
+	global.gag++;
+
+	resolve(loc, sc, &e, &t, &s);
+
+	global.gag--;
+	if (errors != global.errors)
+	{   if (global.gag == 0)
+		global.errors = errors;
+	    return NULL;
+	}
+    }
+    else
+	resolve(loc, sc, &e, &t, &s);
+
+    return s;
+}
+
 
 /***************************** TypeTypeof *****************************/
 
@@ -4380,9 +4408,12 @@
 	return new IntegerExp(e->loc, 0, Type::tint32);
     }
 
+    /* If e.tupleof
+     */
     if (ident == Id::tupleof)
     {
-	/* Create a TupleExp
+	/* Create a TupleExp out of the fields of the struct e:
+	 * (e.field0, e.field1, e.field2, ...)
 	 */
 	e = e->semantic(sc);	// do this before turning on noaccesscheck
 	Expressions *exps = new Expressions;
@@ -4477,6 +4508,14 @@
 	return de;
     }
 
+    Import *timp = s->isImport();
+    if (timp)
+    {
+	e = new DsymbolExp(e->loc, s);
+	e = e->semantic(sc);
+	return e;
+    }
+
     d = s->isDeclaration();
 #ifdef DEBUG
     if (!d)
@@ -4521,9 +4560,7 @@
 
 	// *(&e + offset)
 	accessCheck(e->loc, sc, e, d);
-
-// LDC we don't want dot exprs turned into pointer arithmetic. it complicates things for no apparent gain
-#ifndef IN_LLVM
+#if 0
 	b = new AddrExp(e->loc, e);
 	b->type = e->type->pointerTo();
 	b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
--- a/dmd/mtype.h	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/mtype.h	Tue Jan 06 16:33:51 2009 +0100
@@ -507,6 +507,7 @@
     void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
     void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
     Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
     MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
 };
 
--- a/dmd/opover.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/opover.c	Tue Jan 06 16:33:51 2009 +0100
@@ -1,748 +1,748 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include <complex>
-
-#ifdef __APPLE__
-#define integer_t dmd_integer_t
-#endif
-
-#if IN_GCC || IN_LLVM
-#include "mem.h"
-#elif POSIX
-#include "../root/mem.h"
-#elif _WIN32
-#include "..\root\mem.h"
-#endif
-
-//#include "port.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "id.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "template.h"
-
-static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id);
-static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments);
-static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments);
-static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments);
-
-/******************************** Expression **************************/
-
-
-/***********************************
- * Determine if operands of binary op can be reversed
- * to fit operator overload.
- */
-
-int Expression::isCommutative()
-{
-    return FALSE;	// default is no reverse
-}
-
-/***********************************
- * Get Identifier for operator overload.
- */
-
-Identifier *Expression::opId()
-{
-    assert(0);
-    return NULL;
-}
-
-/***********************************
- * Get Identifier for reverse operator overload,
- * NULL if not supported for this operator.
- */
-
-Identifier *Expression::opId_r()
-{
-    return NULL;
-}
-
-/************************* Operators *****************************/
-
-Identifier *UAddExp::opId()   { return Id::uadd; }
-
-Identifier *NegExp::opId()   { return Id::neg; }
-
-Identifier *ComExp::opId()   { return Id::com; }
-
-Identifier *CastExp::opId()   { return Id::cast; }
-
-Identifier *InExp::opId()     { return Id::opIn; }
-Identifier *InExp::opId_r()     { return Id::opIn_r; }
-
-Identifier *PostExp::opId() { return (op == TOKplusplus)
-				? Id::postinc
-				: Id::postdec; }
-
-int AddExp::isCommutative()  { return TRUE; }
-Identifier *AddExp::opId()   { return Id::add; }
-Identifier *AddExp::opId_r() { return Id::add_r; }
-
-Identifier *MinExp::opId()   { return Id::sub; }
-Identifier *MinExp::opId_r() { return Id::sub_r; }
-
-int MulExp::isCommutative()  { return TRUE; }
-Identifier *MulExp::opId()   { return Id::mul; }
-Identifier *MulExp::opId_r() { return Id::mul_r; }
-
-Identifier *DivExp::opId()   { return Id::div; }
-Identifier *DivExp::opId_r() { return Id::div_r; }
-
-Identifier *ModExp::opId()   { return Id::mod; }
-Identifier *ModExp::opId_r() { return Id::mod_r; }
-
-Identifier *ShlExp::opId()   { return Id::shl; }
-Identifier *ShlExp::opId_r() { return Id::shl_r; }
-
-Identifier *ShrExp::opId()   { return Id::shr; }
-Identifier *ShrExp::opId_r() { return Id::shr_r; }
-
-Identifier *UshrExp::opId()   { return Id::ushr; }
-Identifier *UshrExp::opId_r() { return Id::ushr_r; }
-
-int AndExp::isCommutative()  { return TRUE; }
-Identifier *AndExp::opId()   { return Id::iand; }
-Identifier *AndExp::opId_r() { return Id::iand_r; }
-
-int OrExp::isCommutative()  { return TRUE; }
-Identifier *OrExp::opId()   { return Id::ior; }
-Identifier *OrExp::opId_r() { return Id::ior_r; }
-
-int XorExp::isCommutative()  { return TRUE; }
-Identifier *XorExp::opId()   { return Id::ixor; }
-Identifier *XorExp::opId_r() { return Id::ixor_r; }
-
-Identifier *CatExp::opId()   { return Id::cat; }
-Identifier *CatExp::opId_r() { return Id::cat_r; }
-
-Identifier *    AssignExp::opId()  { return Id::assign;  }
-Identifier * AddAssignExp::opId()  { return Id::addass;  }
-Identifier * MinAssignExp::opId()  { return Id::subass;  }
-Identifier * MulAssignExp::opId()  { return Id::mulass;  }
-Identifier * DivAssignExp::opId()  { return Id::divass;  }
-Identifier * ModAssignExp::opId()  { return Id::modass;  }
-Identifier * AndAssignExp::opId()  { return Id::andass;  }
-Identifier *  OrAssignExp::opId()  { return Id::orass;   }
-Identifier * XorAssignExp::opId()  { return Id::xorass;  }
-Identifier * ShlAssignExp::opId()  { return Id::shlass;  }
-Identifier * ShrAssignExp::opId()  { return Id::shrass;  }
-Identifier *UshrAssignExp::opId()  { return Id::ushrass; }
-Identifier * CatAssignExp::opId()  { return Id::catass;  }
-
-int EqualExp::isCommutative()  { return TRUE; }
-Identifier *EqualExp::opId()   { return Id::eq; }
-
-int CmpExp::isCommutative()  { return TRUE; }
-Identifier *CmpExp::opId()   { return Id::cmp; }
-
-Identifier *ArrayExp::opId()	{ return Id::index; }
-
-
-/************************************
- * Operator overload.
- * Check for operator overload, if so, replace
- * with function call.
- * Return NULL if not an operator overload.
- */
-
-Expression *UnaExp::op_overload(Scope *sc)
-{
-    AggregateDeclaration *ad;
-    Dsymbol *fd;
-    Type *t1 = e1->type->toBasetype();
-
-    if (t1->ty == Tclass)
-    {
-	ad = ((TypeClass *)t1)->sym;
-	goto L1;
-    }
-    else if (t1->ty == Tstruct)
-    {
-	ad = ((TypeStruct *)t1)->sym;
-
-    L1:
-	fd = search_function(ad, opId());
-	if (fd)
-	{
-	    if (op == TOKarray)
-	    {
-		Expression *e;
-		ArrayExp *ae = (ArrayExp *)this;
-
-		e = new DotIdExp(loc, e1, fd->ident);
-		e = new CallExp(loc, e, ae->arguments);
-		e = e->semantic(sc);
-		return e;
-	    }
-	    else
-	    {
-		// Rewrite +e1 as e1.add()
-		return build_overload(loc, sc, e1, NULL, fd->ident);
-	    }
-	}
-    }
-    return NULL;
-}
-
-
-Expression *BinExp::op_overload(Scope *sc)
-{
-    //printf("BinExp::op_overload() (%s)\n", toChars());
-
-    AggregateDeclaration *ad;
-    Type *t1 = e1->type->toBasetype();
-    Type *t2 = e2->type->toBasetype();
-    Identifier *id = opId();
-    Identifier *id_r = opId_r();
-
-    Match m;
-    Expressions args1;
-    Expressions args2;
-    int argsset = 0;
-
-    AggregateDeclaration *ad1;
-    if (t1->ty == Tclass)
-	ad1 = ((TypeClass *)t1)->sym;
-    else if (t1->ty == Tstruct)
-	ad1 = ((TypeStruct *)t1)->sym;
-    else
-	ad1 = NULL;
-
-    AggregateDeclaration *ad2;
-    if (t2->ty == Tclass)
-	ad2 = ((TypeClass *)t2)->sym;
-    else if (t2->ty == Tstruct)
-	ad2 = ((TypeStruct *)t2)->sym;
-    else
-	ad2 = NULL;
-
-    Dsymbol *s = NULL;
-    Dsymbol *s_r = NULL;
-    FuncDeclaration *fd = NULL;
-    TemplateDeclaration *td = NULL;
-    if (ad1 && id)
-    {
-	s = search_function(ad1, id);
-    }
-    if (ad2 && id_r)
-    {
-	s_r = search_function(ad2, id_r);
-    }
-
-    if (s || s_r)
-    {
-	/* Try:
-	 *	a.opfunc(b)
-	 *	b.opfunc_r(a)
-	 * and see which is better.
-	 */
-	Expression *e;
-	FuncDeclaration *lastf;
-
-	args1.setDim(1);
-	args1.data[0] = (void*) e1;
-	args2.setDim(1);
-	args2.data[0] = (void*) e2;
-	argsset = 1;
-
-	memset(&m, 0, sizeof(m));
-	m.last = MATCHnomatch;
-
-	if (s)
-	{
-	    fd = s->isFuncDeclaration();
-	    if (fd)
-	    {
-		overloadResolveX(&m, fd, &args2);
-	    }
-	    else
-	    {   td = s->isTemplateDeclaration();
-		templateResolve(&m, td, sc, loc, NULL, &args2);
-	    }
-	}
-
-	lastf = m.lastf;
-
-	if (s_r)
-	{
-	    fd = s_r->isFuncDeclaration();
-	    if (fd)
-	    {
-		overloadResolveX(&m, fd, &args1);
-	    }
-	    else
-	    {   td = s_r->isTemplateDeclaration();
-		templateResolve(&m, td, sc, loc, NULL, &args1);
-	    }
-	}
-
-	if (m.count > 1)
-	{
-	    // Error, ambiguous
-	    error("overloads %s and %s both match argument list for %s",
-		    m.lastf->type->toChars(),
-		    m.nextf->type->toChars(),
-		    m.lastf->toChars());
-	}
-	else if (m.last == MATCHnomatch)
-	{
-	    m.lastf = m.anyf;
-	}
-
-	if (op == TOKplusplus || op == TOKminusminus)
-	    // Kludge because operator overloading regards e++ and e--
-	    // as unary, but it's implemented as a binary.
-	    // Rewrite (e1 ++ e2) as e1.postinc()
-	    // Rewrite (e1 -- e2) as e1.postdec()
-	    e = build_overload(loc, sc, e1, NULL, id);
-	else if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
-	    // Rewrite (e1 op e2) as e1.opfunc(e2)
-	    e = build_overload(loc, sc, e1, e2, id);
-	else
-	    // Rewrite (e1 op e2) as e2.opfunc_r(e1)
-	    e = build_overload(loc, sc, e2, e1, id_r);
-	return e;
-    }
-
-    if (isCommutative())
-    {
-	s = NULL;
-	s_r = NULL;
-	if (ad1 && id_r)
-	{
-	    s_r = search_function(ad1, id_r);
-	}
-	if (ad2 && id)
-	{
-	    s = search_function(ad2, id);
-	}
-
-	if (s || s_r)
-	{
-	    /* Try:
-	     *	a.opfunc_r(b)
-	     *	b.opfunc(a)
-	     * and see which is better.
-	     */
-	    Expression *e;
-	    FuncDeclaration *lastf;
-
-	    if (!argsset)
-	    {	args1.setDim(1);
-		args1.data[0] = (void*) e1;
-		args2.setDim(1);
-		args2.data[0] = (void*) e2;
-	    }
-
-	    memset(&m, 0, sizeof(m));
-	    m.last = MATCHnomatch;
-
-	    if (s_r)
-	    {
-		fd = s_r->isFuncDeclaration();
-		if (fd)
-		{
-		    overloadResolveX(&m, fd, &args2);
-		}
-		else
-		{   td = s_r->isTemplateDeclaration();
-		    templateResolve(&m, td, sc, loc, NULL, &args2);
-		}
-	    }
-	    lastf = m.lastf;
-
-	    if (s)
-	    {
-		fd = s->isFuncDeclaration();
-		if (fd)
-		{
-		    overloadResolveX(&m, fd, &args1);
-		}
-		else
-		{   td = s->isTemplateDeclaration();
-		    templateResolve(&m, td, sc, loc, NULL, &args1);
-		}
-	    }
-
-	    if (m.count > 1)
-	    {
-		// Error, ambiguous
-		error("overloads %s and %s both match argument list for %s",
-			m.lastf->type->toChars(),
-			m.nextf->type->toChars(),
-			m.lastf->toChars());
-	    }
-	    else if (m.last == MATCHnomatch)
-	    {
-		m.lastf = m.anyf;
-	    }
-
-	    if (lastf && m.lastf == lastf ||
-		id_r && m.last == MATCHnomatch)
-		// Rewrite (e1 op e2) as e1.opfunc_r(e2)
-		e = build_overload(loc, sc, e1, e2, id_r);
-	    else
-		// Rewrite (e1 op e2) as e2.opfunc(e1)
-		e = build_overload(loc, sc, e2, e1, id);
-
-	    // When reversing operands of comparison operators,
-	    // need to reverse the sense of the op
-	    switch (op)
-	    {
-		case TOKlt:	op = TOKgt;	break;
-		case TOKgt:	op = TOKlt;	break;
-		case TOKle:	op = TOKge;	break;
-		case TOKge:	op = TOKle;	break;
-
-		// Floating point compares
-		case TOKule:	op = TOKuge;	 break;
-		case TOKul:	op = TOKug;	 break;
-		case TOKuge:	op = TOKule;	 break;
-		case TOKug:	op = TOKul;	 break;
-
-		// These are symmetric
-		case TOKunord:
-		case TOKlg:
-		case TOKleg:
-		case TOKue:
-		    break;
-	    }
-
-	    return e;
-	}
-    }
-
-    return NULL;
-}
-
-/***********************************
- * Utility to build a function call out of this reference and argument.
- */
-
-static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id)
-{
-    Expression *e;
-
-    //printf("build_overload(id = '%s')\n", id->toChars());
-    //earg->print();
-    //earg->type->print();
-    e = new DotIdExp(loc, ethis, id);
-
-    if (earg)
-	e = new CallExp(loc, e, earg);
-    else
-	e = new CallExp(loc, e);
-
-    e = e->semantic(sc);
-    return e;
-}
-
-/***************************************
- * Search for function funcid in aggregate ad.
- */
-
-Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid)
-{
-    Dsymbol *s;
-    FuncDeclaration *fd;
-    TemplateDeclaration *td;
-
-    s = ad->search(0, funcid, 0);
-    if (s)
-    {	Dsymbol *s2;
-
-	//printf("search_function: s = '%s'\n", s->kind());
-	s2 = s->toAlias();
-	//printf("search_function: s2 = '%s'\n", s2->kind());
-	fd = s2->isFuncDeclaration();
-	if (fd && fd->type->ty == Tfunction)
-	    return fd;
-
-	td = s2->isTemplateDeclaration();
-	if (td)
-	    return td;
-    }
-    return NULL;
-}
-
-
-/*****************************************
- * Given array of arguments and an aggregate type,
- * if any of the argument types are missing, attempt to infer
- * them from the aggregate type.
- */
-
-void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr)
-{
-    if (!arguments || !arguments->dim)
-	return;
-
-    /* Return if no arguments need types.
-     */
-    for (size_t u = 0; 1; u++)
-    {	if (u == arguments->dim)
-	    return;
-	Argument *arg = (Argument *)arguments->data[u];
-	if (!arg->type)
-	    break;
-    }
-
-    AggregateDeclaration *ad;
-    FuncDeclaration *fd;
-
-    Argument *arg = (Argument *)arguments->data[0];
-    Type *taggr = aggr->type;
-    if (!taggr)
-	return;
-    Type *tab = taggr->toBasetype();
-    switch (tab->ty)
-    {
-	case Tarray:
-	case Tsarray:
-	case Ttuple:
-	    if (arguments->dim == 2)
-	    {
-		if (!arg->type)
-		    arg->type = Type::tsize_t;	// key type
-		arg = (Argument *)arguments->data[1];
-	    }
-	    if (!arg->type && tab->ty != Ttuple)
-		arg->type = tab->nextOf();	// value type
-	    break;
-
-	case Taarray:
-	{   TypeAArray *taa = (TypeAArray *)tab;
-
-	    if (arguments->dim == 2)
-	    {
-		if (!arg->type)
-		    arg->type = taa->index;	// key type
-		arg = (Argument *)arguments->data[1];
-	    }
-	    if (!arg->type)
-		arg->type = taa->next;		// value type
-	    break;
-	}
-
-	case Tclass:
-	    ad = ((TypeClass *)tab)->sym;
-	    goto Laggr;
-
-	case Tstruct:
-	    ad = ((TypeStruct *)tab)->sym;
-	    goto Laggr;
-
-	Laggr:
-#if 0
-	    if (arguments->dim == 1)
-	    {
-		if (!arg->type)
-		{
-		    /* Look for an opNext() overload
-		     */
-		    Dsymbol *s = search_function(ad, Id::next);
-		    fd = s ? s->isFuncDeclaration() : NULL;
-		    if (!fd)
-			goto Lapply;
-		    arg->type = fd->type->next;
-		}
-		break;
-	    }
-#endif
-	Lapply:
-	{   /* Look for an
-	     *	int opApply(int delegate(ref Type [, ...]) dg);
-	     * overload
-	     */
-	    Dsymbol *s = search_function(ad,
-			(op == TOKforeach_reverse) ? Id::applyReverse
-						   : Id::apply);
-	    if (s)
-	    {
-		fd = s->isFuncDeclaration();
-		if (fd)
-		    inferApplyArgTypesX(fd, arguments);
-	    }
-	    break;
-	}
-
-	case Tdelegate:
-	{
-	    if (0 && aggr->op == TOKdelegate)
-	    {	DelegateExp *de = (DelegateExp *)aggr;
-
-		fd = de->func->isFuncDeclaration();
-		if (fd)
-		    inferApplyArgTypesX(fd, arguments);
-	    }
-	    else
-	    {
-		inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments);
-	    }
-	    break;
-	}
-
-	default:
-	    break;		// ignore error, caught later
-    }
-}
-
-/********************************
- * Recursive helper function,
- * analogous to func.overloadResolveX().
- */
-
-int fp3(void *param, FuncDeclaration *f)
-{
-    Arguments *arguments = (Arguments *)param;
-    TypeFunction *tf = (TypeFunction *)f->type;
-    if (inferApplyArgTypesY(tf, arguments) == 1)
-	return 0;
-    if (arguments->dim == 0)
-	return 1;
-    return 0;
-}
-
-static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
-{
-    overloadApply(fstart, &fp3, arguments);
-}
-
-#if 0
-static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
-{
-    Declaration *d;
-    Declaration *next;
-
-    for (d = fstart; d; d = next)
-    {
-	FuncDeclaration *f;
-	FuncAliasDeclaration *fa;
-	AliasDeclaration *a;
-
-	fa = d->isFuncAliasDeclaration();
-	if (fa)
-	{
-	    inferApplyArgTypesX(fa->funcalias, arguments);
-	    next = fa->overnext;
-	}
-	else if ((f = d->isFuncDeclaration()) != NULL)
-	{
-	    next = f->overnext;
-
-	    TypeFunction *tf = (TypeFunction *)f->type;
-	    if (inferApplyArgTypesY(tf, arguments) == 1)
-		continue;
-	    if (arguments->dim == 0)
-		return;
-	}
-	else if ((a = d->isAliasDeclaration()) != NULL)
-	{
-	    Dsymbol *s = a->toAlias();
-	    next = s->isDeclaration();
-	    if (next == a)
-		break;
-	    if (next == fstart)
-		break;
-	}
-	else
-	{   d->error("is aliased to a function");
-	    break;
-	}
-    }
-}
-#endif
-
-/******************************
- * Infer arguments from type of function.
- * Returns:
- *	0 match for this function
- *	1 no match for this function
- */
-
-static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments)
-{   size_t nparams;
-    Argument *p;
-
-    if (Argument::dim(tf->parameters) != 1)
-	goto Lnomatch;
-    p = Argument::getNth(tf->parameters, 0);
-    if (p->type->ty != Tdelegate)
-	goto Lnomatch;
-    tf = (TypeFunction *)p->type->nextOf();
-    assert(tf->ty == Tfunction);
-
-    /* We now have tf, the type of the delegate. Match it against
-     * the arguments, filling in missing argument types.
-     */
-    nparams = Argument::dim(tf->parameters);
-    if (nparams == 0 || tf->varargs)
-	goto Lnomatch;		// not enough parameters
-    if (arguments->dim != nparams)
-	goto Lnomatch;		// not enough parameters
-
-    for (size_t u = 0; u < nparams; u++)
-    {
-	Argument *arg = (Argument *)arguments->data[u];
-	Argument *param = Argument::getNth(tf->parameters, u);
-	if (arg->type)
-	{   if (!arg->type->equals(param->type))
-	    {
-		/* Cannot resolve argument types. Indicate an
-		 * error by setting the number of arguments to 0.
-		 */
-		arguments->dim = 0;
-		goto Lmatch;
-	    }
-	    continue;
-	}
-	arg->type = param->type;
-    }
-  Lmatch:
-    return 0;
-
-  Lnomatch:
-    return 1;
-}
-
-/**************************************
- */
-
-static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments)
-{
-    FuncDeclaration *fd;
-
-    assert(td);
-    fd = td->deduceFunctionTemplate(sc, loc, targsi, arguments);
-    if (!fd)
-	return;
-    m->anyf = fd;
-    if (m->last >= MATCHexact)
-    {
-	m->nextf = fd;
-	m->count++;
-    }
-    else
-    {
-	m->last = MATCHexact;
-	m->lastf = fd;
-	m->count = 1;
-    }
-}
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <complex>
+
+#ifdef __APPLE__
+#define integer_t dmd_integer_t
+#endif
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#elif POSIX
+#include "../root/mem.h"
+#elif _WIN32
+#include "..\root\mem.h"
+#endif
+
+//#include "port.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "id.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+
+static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id);
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments);
+static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments);
+static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments);
+
+/******************************** Expression **************************/
+
+
+/***********************************
+ * Determine if operands of binary op can be reversed
+ * to fit operator overload.
+ */
+
+int Expression::isCommutative()
+{
+    return FALSE;	// default is no reverse
+}
+
+/***********************************
+ * Get Identifier for operator overload.
+ */
+
+Identifier *Expression::opId()
+{
+    assert(0);
+    return NULL;
+}
+
+/***********************************
+ * Get Identifier for reverse operator overload,
+ * NULL if not supported for this operator.
+ */
+
+Identifier *Expression::opId_r()
+{
+    return NULL;
+}
+
+/************************* Operators *****************************/
+
+Identifier *UAddExp::opId()   { return Id::uadd; }
+
+Identifier *NegExp::opId()   { return Id::neg; }
+
+Identifier *ComExp::opId()   { return Id::com; }
+
+Identifier *CastExp::opId()   { return Id::cast; }
+
+Identifier *InExp::opId()     { return Id::opIn; }
+Identifier *InExp::opId_r()     { return Id::opIn_r; }
+
+Identifier *PostExp::opId() { return (op == TOKplusplus)
+				? Id::postinc
+				: Id::postdec; }
+
+int AddExp::isCommutative()  { return TRUE; }
+Identifier *AddExp::opId()   { return Id::add; }
+Identifier *AddExp::opId_r() { return Id::add_r; }
+
+Identifier *MinExp::opId()   { return Id::sub; }
+Identifier *MinExp::opId_r() { return Id::sub_r; }
+
+int MulExp::isCommutative()  { return TRUE; }
+Identifier *MulExp::opId()   { return Id::mul; }
+Identifier *MulExp::opId_r() { return Id::mul_r; }
+
+Identifier *DivExp::opId()   { return Id::div; }
+Identifier *DivExp::opId_r() { return Id::div_r; }
+
+Identifier *ModExp::opId()   { return Id::mod; }
+Identifier *ModExp::opId_r() { return Id::mod_r; }
+
+Identifier *ShlExp::opId()   { return Id::shl; }
+Identifier *ShlExp::opId_r() { return Id::shl_r; }
+
+Identifier *ShrExp::opId()   { return Id::shr; }
+Identifier *ShrExp::opId_r() { return Id::shr_r; }
+
+Identifier *UshrExp::opId()   { return Id::ushr; }
+Identifier *UshrExp::opId_r() { return Id::ushr_r; }
+
+int AndExp::isCommutative()  { return TRUE; }
+Identifier *AndExp::opId()   { return Id::iand; }
+Identifier *AndExp::opId_r() { return Id::iand_r; }
+
+int OrExp::isCommutative()  { return TRUE; }
+Identifier *OrExp::opId()   { return Id::ior; }
+Identifier *OrExp::opId_r() { return Id::ior_r; }
+
+int XorExp::isCommutative()  { return TRUE; }
+Identifier *XorExp::opId()   { return Id::ixor; }
+Identifier *XorExp::opId_r() { return Id::ixor_r; }
+
+Identifier *CatExp::opId()   { return Id::cat; }
+Identifier *CatExp::opId_r() { return Id::cat_r; }
+
+Identifier *    AssignExp::opId()  { return Id::assign;  }
+Identifier * AddAssignExp::opId()  { return Id::addass;  }
+Identifier * MinAssignExp::opId()  { return Id::subass;  }
+Identifier * MulAssignExp::opId()  { return Id::mulass;  }
+Identifier * DivAssignExp::opId()  { return Id::divass;  }
+Identifier * ModAssignExp::opId()  { return Id::modass;  }
+Identifier * AndAssignExp::opId()  { return Id::andass;  }
+Identifier *  OrAssignExp::opId()  { return Id::orass;   }
+Identifier * XorAssignExp::opId()  { return Id::xorass;  }
+Identifier * ShlAssignExp::opId()  { return Id::shlass;  }
+Identifier * ShrAssignExp::opId()  { return Id::shrass;  }
+Identifier *UshrAssignExp::opId()  { return Id::ushrass; }
+Identifier * CatAssignExp::opId()  { return Id::catass;  }
+
+int EqualExp::isCommutative()  { return TRUE; }
+Identifier *EqualExp::opId()   { return Id::eq; }
+
+int CmpExp::isCommutative()  { return TRUE; }
+Identifier *CmpExp::opId()   { return Id::cmp; }
+
+Identifier *ArrayExp::opId()	{ return Id::index; }
+
+
+/************************************
+ * Operator overload.
+ * Check for operator overload, if so, replace
+ * with function call.
+ * Return NULL if not an operator overload.
+ */
+
+Expression *UnaExp::op_overload(Scope *sc)
+{
+    AggregateDeclaration *ad;
+    Dsymbol *fd;
+    Type *t1 = e1->type->toBasetype();
+
+    if (t1->ty == Tclass)
+    {
+	ad = ((TypeClass *)t1)->sym;
+	goto L1;
+    }
+    else if (t1->ty == Tstruct)
+    {
+	ad = ((TypeStruct *)t1)->sym;
+
+    L1:
+	fd = search_function(ad, opId());
+	if (fd)
+	{
+	    if (op == TOKarray)
+	    {
+		Expression *e;
+		ArrayExp *ae = (ArrayExp *)this;
+
+		e = new DotIdExp(loc, e1, fd->ident);
+		e = new CallExp(loc, e, ae->arguments);
+		e = e->semantic(sc);
+		return e;
+	    }
+	    else
+	    {
+		// Rewrite +e1 as e1.add()
+		return build_overload(loc, sc, e1, NULL, fd->ident);
+	    }
+	}
+    }
+    return NULL;
+}
+
+
+Expression *BinExp::op_overload(Scope *sc)
+{
+    //printf("BinExp::op_overload() (%s)\n", toChars());
+
+    AggregateDeclaration *ad;
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+    Identifier *id = opId();
+    Identifier *id_r = opId_r();
+
+    Match m;
+    Expressions args1;
+    Expressions args2;
+    int argsset = 0;
+
+    AggregateDeclaration *ad1;
+    if (t1->ty == Tclass)
+	ad1 = ((TypeClass *)t1)->sym;
+    else if (t1->ty == Tstruct)
+	ad1 = ((TypeStruct *)t1)->sym;
+    else
+	ad1 = NULL;
+
+    AggregateDeclaration *ad2;
+    if (t2->ty == Tclass)
+	ad2 = ((TypeClass *)t2)->sym;
+    else if (t2->ty == Tstruct)
+	ad2 = ((TypeStruct *)t2)->sym;
+    else
+	ad2 = NULL;
+
+    Dsymbol *s = NULL;
+    Dsymbol *s_r = NULL;
+    FuncDeclaration *fd = NULL;
+    TemplateDeclaration *td = NULL;
+    if (ad1 && id)
+    {
+	s = search_function(ad1, id);
+    }
+    if (ad2 && id_r)
+    {
+	s_r = search_function(ad2, id_r);
+    }
+
+    if (s || s_r)
+    {
+	/* Try:
+	 *	a.opfunc(b)
+	 *	b.opfunc_r(a)
+	 * and see which is better.
+	 */
+	Expression *e;
+	FuncDeclaration *lastf;
+
+	args1.setDim(1);
+	args1.data[0] = (void*) e1;
+	args2.setDim(1);
+	args2.data[0] = (void*) e2;
+	argsset = 1;
+
+	memset(&m, 0, sizeof(m));
+	m.last = MATCHnomatch;
+
+	if (s)
+	{
+	    fd = s->isFuncDeclaration();
+	    if (fd)
+	    {
+		overloadResolveX(&m, fd, &args2);
+	    }
+	    else
+	    {   td = s->isTemplateDeclaration();
+		templateResolve(&m, td, sc, loc, NULL, &args2);
+	    }
+	}
+
+	lastf = m.lastf;
+
+	if (s_r)
+	{
+	    fd = s_r->isFuncDeclaration();
+	    if (fd)
+	    {
+		overloadResolveX(&m, fd, &args1);
+	    }
+	    else
+	    {   td = s_r->isTemplateDeclaration();
+		templateResolve(&m, td, sc, loc, NULL, &args1);
+	    }
+	}
+
+	if (m.count > 1)
+	{
+	    // Error, ambiguous
+	    error("overloads %s and %s both match argument list for %s",
+		    m.lastf->type->toChars(),
+		    m.nextf->type->toChars(),
+		    m.lastf->toChars());
+	}
+	else if (m.last == MATCHnomatch)
+	{
+	    m.lastf = m.anyf;
+	}
+
+	if (op == TOKplusplus || op == TOKminusminus)
+	    // Kludge because operator overloading regards e++ and e--
+	    // as unary, but it's implemented as a binary.
+	    // Rewrite (e1 ++ e2) as e1.postinc()
+	    // Rewrite (e1 -- e2) as e1.postdec()
+	    e = build_overload(loc, sc, e1, NULL, id);
+	else if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
+	    // Rewrite (e1 op e2) as e1.opfunc(e2)
+	    e = build_overload(loc, sc, e1, e2, id);
+	else
+	    // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+	    e = build_overload(loc, sc, e2, e1, id_r);
+	return e;
+    }
+
+    if (isCommutative())
+    {
+	s = NULL;
+	s_r = NULL;
+	if (ad1 && id_r)
+	{
+	    s_r = search_function(ad1, id_r);
+	}
+	if (ad2 && id)
+	{
+	    s = search_function(ad2, id);
+	}
+
+	if (s || s_r)
+	{
+	    /* Try:
+	     *	a.opfunc_r(b)
+	     *	b.opfunc(a)
+	     * and see which is better.
+	     */
+	    Expression *e;
+	    FuncDeclaration *lastf;
+
+	    if (!argsset)
+	    {	args1.setDim(1);
+		args1.data[0] = (void*) e1;
+		args2.setDim(1);
+		args2.data[0] = (void*) e2;
+	    }
+
+	    memset(&m, 0, sizeof(m));
+	    m.last = MATCHnomatch;
+
+	    if (s_r)
+	    {
+		fd = s_r->isFuncDeclaration();
+		if (fd)
+		{
+		    overloadResolveX(&m, fd, &args2);
+		}
+		else
+		{   td = s_r->isTemplateDeclaration();
+		    templateResolve(&m, td, sc, loc, NULL, &args2);
+		}
+	    }
+	    lastf = m.lastf;
+
+	    if (s)
+	    {
+		fd = s->isFuncDeclaration();
+		if (fd)
+		{
+		    overloadResolveX(&m, fd, &args1);
+		}
+		else
+		{   td = s->isTemplateDeclaration();
+		    templateResolve(&m, td, sc, loc, NULL, &args1);
+		}
+	    }
+
+	    if (m.count > 1)
+	    {
+		// Error, ambiguous
+		error("overloads %s and %s both match argument list for %s",
+			m.lastf->type->toChars(),
+			m.nextf->type->toChars(),
+			m.lastf->toChars());
+	    }
+	    else if (m.last == MATCHnomatch)
+	    {
+		m.lastf = m.anyf;
+	    }
+
+	    if (lastf && m.lastf == lastf ||
+		id_r && m.last == MATCHnomatch)
+		// Rewrite (e1 op e2) as e1.opfunc_r(e2)
+		e = build_overload(loc, sc, e1, e2, id_r);
+	    else
+		// Rewrite (e1 op e2) as e2.opfunc(e1)
+		e = build_overload(loc, sc, e2, e1, id);
+
+	    // When reversing operands of comparison operators,
+	    // need to reverse the sense of the op
+	    switch (op)
+	    {
+		case TOKlt:	op = TOKgt;	break;
+		case TOKgt:	op = TOKlt;	break;
+		case TOKle:	op = TOKge;	break;
+		case TOKge:	op = TOKle;	break;
+
+		// Floating point compares
+		case TOKule:	op = TOKuge;	 break;
+		case TOKul:	op = TOKug;	 break;
+		case TOKuge:	op = TOKule;	 break;
+		case TOKug:	op = TOKul;	 break;
+
+		// These are symmetric
+		case TOKunord:
+		case TOKlg:
+		case TOKleg:
+		case TOKue:
+		    break;
+	    }
+
+	    return e;
+	}
+    }
+
+    return NULL;
+}
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+
+static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id)
+{
+    Expression *e;
+
+    //printf("build_overload(id = '%s')\n", id->toChars());
+    //earg->print();
+    //earg->type->print();
+    e = new DotIdExp(loc, ethis, id);
+
+    if (earg)
+	e = new CallExp(loc, e, earg);
+    else
+	e = new CallExp(loc, e);
+
+    e = e->semantic(sc);
+    return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+
+Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid)
+{
+    Dsymbol *s;
+    FuncDeclaration *fd;
+    TemplateDeclaration *td;
+
+    s = ad->search(0, funcid, 0);
+    if (s)
+    {	Dsymbol *s2;
+
+	//printf("search_function: s = '%s'\n", s->kind());
+	s2 = s->toAlias();
+	//printf("search_function: s2 = '%s'\n", s2->kind());
+	fd = s2->isFuncDeclaration();
+	if (fd && fd->type->ty == Tfunction)
+	    return fd;
+
+	td = s2->isTemplateDeclaration();
+	if (td)
+	    return td;
+    }
+    return NULL;
+}
+
+
+/*****************************************
+ * Given array of arguments and an aggregate type,
+ * if any of the argument types are missing, attempt to infer
+ * them from the aggregate type.
+ */
+
+void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr)
+{
+    if (!arguments || !arguments->dim)
+	return;
+
+    /* Return if no arguments need types.
+     */
+    for (size_t u = 0; 1; u++)
+    {	if (u == arguments->dim)
+	    return;
+	Argument *arg = (Argument *)arguments->data[u];
+	if (!arg->type)
+	    break;
+    }
+
+    AggregateDeclaration *ad;
+    FuncDeclaration *fd;
+
+    Argument *arg = (Argument *)arguments->data[0];
+    Type *taggr = aggr->type;
+    if (!taggr)
+	return;
+    Type *tab = taggr->toBasetype();
+    switch (tab->ty)
+    {
+	case Tarray:
+	case Tsarray:
+	case Ttuple:
+	    if (arguments->dim == 2)
+	    {
+		if (!arg->type)
+		    arg->type = Type::tsize_t;	// key type
+		arg = (Argument *)arguments->data[1];
+	    }
+	    if (!arg->type && tab->ty != Ttuple)
+		arg->type = tab->nextOf();	// value type
+	    break;
+
+	case Taarray:
+	{   TypeAArray *taa = (TypeAArray *)tab;
+
+	    if (arguments->dim == 2)
+	    {
+		if (!arg->type)
+		    arg->type = taa->index;	// key type
+		arg = (Argument *)arguments->data[1];
+	    }
+	    if (!arg->type)
+		arg->type = taa->next;		// value type
+	    break;
+	}
+
+	case Tclass:
+	    ad = ((TypeClass *)tab)->sym;
+	    goto Laggr;
+
+	case Tstruct:
+	    ad = ((TypeStruct *)tab)->sym;
+	    goto Laggr;
+
+	Laggr:
+#if 0
+	    if (arguments->dim == 1)
+	    {
+		if (!arg->type)
+		{
+		    /* Look for an opNext() overload
+		     */
+		    Dsymbol *s = search_function(ad, Id::next);
+		    fd = s ? s->isFuncDeclaration() : NULL;
+		    if (!fd)
+			goto Lapply;
+		    arg->type = fd->type->next;
+		}
+		break;
+	    }
+#endif
+	Lapply:
+	{   /* Look for an
+	     *	int opApply(int delegate(ref Type [, ...]) dg);
+	     * overload
+	     */
+	    Dsymbol *s = search_function(ad,
+			(op == TOKforeach_reverse) ? Id::applyReverse
+						   : Id::apply);
+	    if (s)
+	    {
+		fd = s->isFuncDeclaration();
+		if (fd)
+		    inferApplyArgTypesX(fd, arguments);
+	    }
+	    break;
+	}
+
+	case Tdelegate:
+	{
+	    if (0 && aggr->op == TOKdelegate)
+	    {	DelegateExp *de = (DelegateExp *)aggr;
+
+		fd = de->func->isFuncDeclaration();
+		if (fd)
+		    inferApplyArgTypesX(fd, arguments);
+	    }
+	    else
+	    {
+		inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments);
+	    }
+	    break;
+	}
+
+	default:
+	    break;		// ignore error, caught later
+    }
+}
+
+/********************************
+ * Recursive helper function,
+ * analogous to func.overloadResolveX().
+ */
+
+int fp3(void *param, FuncDeclaration *f)
+{
+    Arguments *arguments = (Arguments *)param;
+    TypeFunction *tf = (TypeFunction *)f->type;
+    if (inferApplyArgTypesY(tf, arguments) == 1)
+	return 0;
+    if (arguments->dim == 0)
+	return 1;
+    return 0;
+}
+
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
+{
+    overloadApply(fstart, &fp3, arguments);
+}
+
+#if 0
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
+{
+    Declaration *d;
+    Declaration *next;
+
+    for (d = fstart; d; d = next)
+    {
+	FuncDeclaration *f;
+	FuncAliasDeclaration *fa;
+	AliasDeclaration *a;
+
+	fa = d->isFuncAliasDeclaration();
+	if (fa)
+	{
+	    inferApplyArgTypesX(fa->funcalias, arguments);
+	    next = fa->overnext;
+	}
+	else if ((f = d->isFuncDeclaration()) != NULL)
+	{
+	    next = f->overnext;
+
+	    TypeFunction *tf = (TypeFunction *)f->type;
+	    if (inferApplyArgTypesY(tf, arguments) == 1)
+		continue;
+	    if (arguments->dim == 0)
+		return;
+	}
+	else if ((a = d->isAliasDeclaration()) != NULL)
+	{
+	    Dsymbol *s = a->toAlias();
+	    next = s->isDeclaration();
+	    if (next == a)
+		break;
+	    if (next == fstart)
+		break;
+	}
+	else
+	{   d->error("is aliased to a function");
+	    break;
+	}
+    }
+}
+#endif
+
+/******************************
+ * Infer arguments from type of function.
+ * Returns:
+ *	0 match for this function
+ *	1 no match for this function
+ */
+
+static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments)
+{   size_t nparams;
+    Argument *p;
+
+    if (Argument::dim(tf->parameters) != 1)
+	goto Lnomatch;
+    p = Argument::getNth(tf->parameters, 0);
+    if (p->type->ty != Tdelegate)
+	goto Lnomatch;
+    tf = (TypeFunction *)p->type->nextOf();
+    assert(tf->ty == Tfunction);
+
+    /* We now have tf, the type of the delegate. Match it against
+     * the arguments, filling in missing argument types.
+     */
+    nparams = Argument::dim(tf->parameters);
+    if (nparams == 0 || tf->varargs)
+	goto Lnomatch;		// not enough parameters
+    if (arguments->dim != nparams)
+	goto Lnomatch;		// not enough parameters
+
+    for (size_t u = 0; u < nparams; u++)
+    {
+	Argument *arg = (Argument *)arguments->data[u];
+	Argument *param = Argument::getNth(tf->parameters, u);
+	if (arg->type)
+	{   if (!arg->type->equals(param->type))
+	    {
+		/* Cannot resolve argument types. Indicate an
+		 * error by setting the number of arguments to 0.
+		 */
+		arguments->dim = 0;
+		goto Lmatch;
+	    }
+	    continue;
+	}
+	arg->type = param->type;
+    }
+  Lmatch:
+    return 0;
+
+  Lnomatch:
+    return 1;
+}
+
+/**************************************
+ */
+
+static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments)
+{
+    FuncDeclaration *fd;
+
+    assert(td);
+    fd = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments);
+    if (!fd)
+	return;
+    m->anyf = fd;
+    if (m->last >= MATCHexact)
+    {
+	m->nextf = fd;
+	m->count++;
+    }
+    else
+    {
+	m->last = MATCHexact;
+	m->lastf = fd;
+	m->count = 1;
+    }
+}
+
--- a/dmd/optimize.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/optimize.c	Tue Jan 06 16:33:51 2009 +0100
@@ -278,19 +278,35 @@
 
 Expression *DotVarExp::optimize(int result)
 {
+    //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars());
     e1 = e1->optimize(result);
 
-    // Constant fold structliteral.member
+#if DMDV2
+    if (e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	Expression *e = expandVar(result, v);
+	if (e && e->op == TOKstructliteral)
+	{   StructLiteralExp *sle = (StructLiteralExp *)e;
+	    VarDeclaration *vf = var->isVarDeclaration();
+	    if (vf)
+	    {
+		e = sle->getField(type, vf->offset);
+		if (e != EXP_CANT_INTERPRET)
+		    return e;
+	    }
+	}
+    }
+    else
+#endif
     if (e1->op == TOKstructliteral)
-    {	StructLiteralExp *se = (StructLiteralExp *)e1;
-
-	VarDeclaration* v;
-	if (v = var->isVarDeclaration())
+    {   StructLiteralExp *sle = (StructLiteralExp *)e1;
+	VarDeclaration *vf = var->isVarDeclaration();
+	if (vf)
 	{
-	    Expression *e = se->getField(type, v->offset);
-	    if (!e)
-		e = EXP_CANT_INTERPRET;
-	    return e;
+	    Expression *e = sle->getField(type, vf->offset);
+	    if (e != EXP_CANT_INTERPRET)
+		return e;
 	}
     }
 
@@ -322,6 +338,7 @@
     //printf("CastExp::optimize(result = %d) %s\n", result, toChars());
     //printf("from %s to %s\n", type->toChars(), to->toChars());
     //printf("from %s\n", type->toChars());
+    //printf("e1->type %s\n", e1->type->toChars());
     //printf("type = %p\n", type);
     assert(type);
     enum TOK op1 = e1->op;
--- a/dmd/statement.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/statement.c	Tue Jan 06 16:33:51 2009 +0100
@@ -124,13 +124,6 @@
     return BEany;
 }
 
-// TRUE if statement may fall off the end without a throw or return
-
-int Statement::fallOffEnd()
-{
-    return TRUE;
-}
-
 // TRUE if statement 'comes from' somewhere else, like a goto
 
 int Statement::comeFrom()
@@ -227,21 +220,6 @@
     return result;
 }
 
-int ExpStatement::fallOffEnd()
-{
-    if (exp)
-    {
-	if (exp->op == TOKassert)
-	{   AssertExp *a = (AssertExp *)exp;
-
-	    if (a->e1->isBool(FALSE))	// if it's an assert(0)
-		return FALSE;
-	}
-	else if (exp->op == TOKhalt)
-	    return FALSE;
-    }
-    return TRUE;
-}
 
 /******************************** CompileStatement ***************************/
 
@@ -574,25 +552,6 @@
     return result;
 }
 
-int CompoundStatement::fallOffEnd()
-{   int falloff = TRUE;
-
-    //printf("CompoundStatement::fallOffEnd() %s\n", toChars());
-    for (int i = 0; i < statements->dim; i++)
-    {	Statement *s = (Statement *)statements->data[i];
-
-	if (!s)
-	    continue;
-
-	if (!falloff && global.params.warnings && !s->comeFrom())
-	{
-	    warning("%s: statement is not reachable", s->loc.toChars());
-	}
-	falloff = s->fallOffEnd();
-    }
-    return falloff;
-}
-
 int CompoundStatement::comeFrom()
 {   int comefrom = FALSE;
 
@@ -710,18 +669,6 @@
     return result;
 }
 
-int UnrolledLoopStatement::fallOffEnd()
-{
-    //printf("UnrolledLoopStatement::fallOffEnd()\n");
-    for (size_t i = 0; i < statements->dim; i++)
-    {	Statement *s = (Statement *)statements->data[i];
-
-	if (s)
-	    s->fallOffEnd();
-    }
-    return TRUE;
-}
-
 int UnrolledLoopStatement::comeFrom()
 {   int comefrom = FALSE;
 
@@ -815,11 +762,6 @@
     return statement ? statement->blockExit() : BEfallthru;
 }
 
-int ScopeStatement::fallOffEnd()
-{
-    return statement ? statement->fallOffEnd() : TRUE;
-}
-
 int ScopeStatement::comeFrom()
 {
     //printf("ScopeStatement::comeFrom()\n");
@@ -945,13 +887,6 @@
     return result;
 }
 
-int WhileStatement::fallOffEnd()
-{
-    if (body)
-	body->fallOffEnd();
-    return TRUE;
-}
-
 int WhileStatement::comeFrom()
 {
     if (body)
@@ -1040,13 +975,6 @@
     return result;
 }
 
-int DoStatement::fallOffEnd()
-{
-    if (body)
-	body->fallOffEnd();
-    return TRUE;
-}
-
 int DoStatement::comeFrom()
 {
     if (body)
@@ -1177,13 +1105,6 @@
     return result;
 }
 
-int ForStatement::fallOffEnd()
-{
-    if (body)
-	body->fallOffEnd();
-    return TRUE;
-}
-
 int ForStatement::comeFrom()
 {
     //printf("ForStatement::comeFrom()\n");
@@ -1878,13 +1799,6 @@
     return result;
 }
 
-int ForeachStatement::fallOffEnd()
-{
-    if (body)
-	body->fallOffEnd();
-    return TRUE;
-}
-
 int ForeachStatement::comeFrom()
 {
     if (body)
@@ -2042,15 +1956,6 @@
     return result;
 }
 
-int IfStatement::fallOffEnd()
-{
-    if (!ifbody || ifbody->fallOffEnd() ||
-	!elsebody || elsebody->fallOffEnd())
-	return TRUE;
-    return FALSE;
-}
-
-
 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("if (");
@@ -2268,13 +2173,6 @@
     return result;
 }
 
-int PragmaStatement::fallOffEnd()
-{
-    if (body)
-	return body->fallOffEnd();
-    return TRUE;
-}
-
 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("pragma (");
@@ -2475,13 +2373,6 @@
     return result;
 }
 
-int SwitchStatement::fallOffEnd()
-{
-    if (body)
-	body->fallOffEnd();
-    return TRUE;	// need to do this better
-}
-
 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("switch (");
@@ -2586,11 +2477,6 @@
     return statement->blockExit();
 }
 
-int CaseStatement::fallOffEnd()
-{
-    return statement->fallOffEnd();
-}
-
 int CaseStatement::comeFrom()
 {
     return TRUE;
@@ -2650,11 +2536,6 @@
     return statement->blockExit();
 }
 
-int DefaultStatement::fallOffEnd()
-{
-    return statement->fallOffEnd();
-}
-
 int DefaultStatement::comeFrom()
 {
     return TRUE;
@@ -2695,11 +2576,6 @@
     return BEgoto;
 }
 
-int GotoDefaultStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("goto default;\n");
@@ -2749,11 +2625,6 @@
     return BEgoto;
 }
 
-int GotoCaseStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("goto case");
@@ -2777,11 +2648,6 @@
     return BEthrow;
 }
 
-int SwitchErrorStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("SwitchErrorStatement::toCBuffer()");
@@ -3056,11 +2922,6 @@
     return result;
 }
 
-int ReturnStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->printf("return ");
@@ -3155,11 +3016,6 @@
     return ident ? BEgoto : BEbreak;
 }
 
-int BreakStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("break");
@@ -3263,11 +3119,6 @@
     return ident ? BEgoto : BEcontinue;
 }
 
-int ContinueStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("continue");
@@ -3358,11 +3209,6 @@
     return body ? body->blockExit() : BEfallthru;
 }
 
-int SynchronizedStatement::fallOffEnd()
-{
-    return body ? body->fallOffEnd() : TRUE;
-}
-
 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("synchronized");
@@ -3480,11 +3326,6 @@
     return result;
 }
 
-int WithStatement::fallOffEnd()
-{
-    return body ? body->fallOffEnd() : TRUE;
-}
-
 /******************************** TryCatchStatement ***************************/
 
 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
@@ -3556,22 +3397,6 @@
     return result;
 }
 
-int TryCatchStatement::fallOffEnd()
-{
-    int result = FALSE;
-
-    if (body)
-	result = body->fallOffEnd();
-    for (int i = 0; i < catches->dim; i++)
-    {   Catch *c;
-
-	c = (Catch *)catches->data[i];
-	if (c->handler)
-	    result |= c->handler->fallOffEnd();
-    }
-    return result;
-}
-
 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("try");
@@ -3728,18 +3553,11 @@
 
 int TryFinallyStatement::blockExit()
 {
-    int result = body->blockExit();
-    return result;
+    if (body)
+	return body->blockExit();
+    return BEfallthru;
 }
 
-int TryFinallyStatement::fallOffEnd()
-{   int result;
-
-    result = body ? body->fallOffEnd() : TRUE;
-//    if (finalbody)
-//	result = finalbody->fallOffEnd();
-    return result;
-}
 
 /****************************** OnScopeStatement ***************************/
 
@@ -3861,11 +3679,6 @@
     return BEthrow;  // obviously
 }
 
-int ThrowStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->printf("throw ");
@@ -3924,11 +3737,6 @@
     return statement ? statement->blockExit() : BEfallthru;
 }
 
-int VolatileStatement::fallOffEnd()
-{
-    return statement ? statement->fallOffEnd() : TRUE;
-}
-
 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("volatile");
@@ -3993,11 +3801,6 @@
     return BEgoto;
 }
 
-int GotoStatement::fallOffEnd()
-{
-    return FALSE;
-}
-
 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writestring("goto ");
@@ -4087,11 +3890,6 @@
     return statement ? statement->blockExit() : BEfallthru;
 }
 
-int LabelStatement::fallOffEnd()
-{
-    return statement ? statement->fallOffEnd() : TRUE;
-}
-
 int LabelStatement::comeFrom()
 {
     //printf("LabelStatement::comeFrom()\n");
--- a/dmd/statement.h	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/statement.h	Tue Jan 06 16:33:51 2009 +0100
@@ -148,7 +148,6 @@
     virtual int hasBreak();
     virtual int hasContinue();
     virtual int usesEH();
-    virtual int fallOffEnd();
     virtual int blockExit();
     virtual int comeFrom();
     virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
@@ -179,7 +178,6 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Statement *semantic(Scope *sc);
     Expression *interpret(InterState *istate);
-    int fallOffEnd();
     int blockExit();
 
     int inlineCost(InlineCostState *ics);
@@ -225,7 +223,6 @@
     virtual Statement *semantic(Scope *sc);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     virtual Statements *flatten(Scope *sc);
     ReturnStatement *isReturnStatement();
@@ -255,7 +252,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -280,7 +276,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
 
@@ -302,7 +297,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -325,7 +319,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -351,7 +344,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -384,7 +376,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -413,7 +404,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -440,7 +430,6 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     IfStatement *isIfStatement() { return this; }
 
     int inlineCost(InlineCostState *ics);
@@ -477,7 +466,6 @@
     Statement *semantic(Scope *sc);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
 
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 };
@@ -511,7 +499,6 @@
     int hasBreak();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
@@ -533,7 +520,6 @@
     int compare(Object *obj);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -561,7 +547,6 @@
     Statement *semantic(Scope *sc);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
@@ -584,7 +569,6 @@
     Statement *semantic(Scope *sc);
     Expression *interpret(InterState *istate);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
@@ -602,7 +586,6 @@
     Statement *semantic(Scope *sc);
     Expression *interpret(InterState *istate);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
@@ -612,7 +595,6 @@
 {
     SwitchErrorStatement(Loc loc);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
@@ -628,7 +610,6 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Statement *semantic(Scope *sc);
     int blockExit();
-    int fallOffEnd();
     Expression *interpret(InterState *istate);
 
     int inlineCost(InlineCostState *ics);
@@ -650,7 +631,6 @@
     Statement *semantic(Scope *sc);
     Expression *interpret(InterState *istate);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
@@ -669,7 +649,6 @@
     Statement *semantic(Scope *sc);
     Expression *interpret(InterState *istate);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
@@ -691,7 +670,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     Statement *inlineScan(InlineScanState *iss);
@@ -715,7 +693,6 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -733,7 +710,6 @@
     int hasBreak();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -771,7 +747,6 @@
     int hasContinue();
     int usesEH();
     int blockExit();
-    int fallOffEnd();
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -803,7 +778,6 @@
     Statement *semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     int blockExit();
-    int fallOffEnd();
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -820,7 +794,6 @@
     Statement *semantic(Scope *sc);
     Statements *flatten(Scope *sc);
     int blockExit();
-    int fallOffEnd();
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     Statement *inlineScan(InlineScanState *iss);
@@ -839,7 +812,6 @@
     Statement *syntaxCopy();
     Statement *semantic(Scope *sc);
     int blockExit();
-    int fallOffEnd();
     Expression *interpret(InterState *istate);
 
     void toIR(IRState *irs);
@@ -862,7 +834,6 @@
     Statements *flatten(Scope *sc);
     int usesEH();
     int blockExit();
-    int fallOffEnd();
     int comeFrom();
     Expression *interpret(InterState *istate);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
--- a/dmd/template.c	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/template.c	Tue Jan 06 16:33:51 2009 +0100
@@ -201,8 +201,10 @@
 		goto Lnomatch;
 	}
     }
+    //printf("match\n");
     return 1;	// match
 Lnomatch:
+    //printf("nomatch\n");
     return 0;	// nomatch;
 }
 
@@ -320,7 +322,9 @@
 
     if (sc->func)
     {
+#if DMDV1
 	error("cannot declare template at function scope %s", sc->func->toChars());
+#endif
     }
 
     if (/*global.params.useArrayBounds &&*/ sc->module)
@@ -551,7 +555,9 @@
 
     if (!flag)
     {
-	// Any parameter left without a type gets the type of its corresponding arg
+	/* Any parameter left without a type gets the type of
+	 * its corresponding arg
+	 */
 	for (int i = 0; i < dedtypes_dim; i++)
 	{
 	    if (!dedtypes->data[i])
@@ -561,6 +567,25 @@
 	}
     }
 
+#if DMDV2
+    if (m && constraint && !(flag & 1))
+    {	/* Check to see if constraint is satisfied.
+	 */
+	Expression *e = constraint->syntaxCopy();
+	paramscope->flags |= SCOPEstaticif;
+	e = e->semantic(paramscope);
+	e = e->optimize(WANTvalue | WANTinterpret);
+        if (e->isBool(TRUE))
+            ;
+        else if (e->isBool(FALSE))
+            goto Lnomatch;
+        else
+        {
+            e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars());
+        }
+    }
+#endif
+
 #if LOGM
     // Print out the results
     printf("--------------------------\n");
@@ -674,7 +699,9 @@
 /*************************************************
  * Match function arguments against a specific template function.
  * Input:
+ *	loc		instantiation location
  *	targsi		Expression/Type initial list of template arguments
+ *	ethis		'this' argument if !NULL
  *	fargs		arguments to function
  * Output:
  *	dedargs		Expression/Type deduced template arguments
@@ -682,7 +709,8 @@
  *	match level
  */
 
-MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs,
+MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi,
+	Expression *ethis, Expressions *fargs,
 	Objects *dedargs)
 {
     size_t i;
@@ -824,6 +852,27 @@
     }
 
 L2:
+#if DMDV2
+    // Match 'ethis' to any TemplateThisParameter's
+    if (ethis)
+    {
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    TemplateThisParameter *ttp = tp->isTemplateThisParameter();
+	    if (ttp)
+	    {	MATCH m;
+
+		Type *t = new TypeIdentifier(0, ttp->ident);
+		m = ethis->type->deduceType(scope, t, parameters, &dedtypes);
+		if (!m)
+		    goto Lnomatch;
+		if (m < match)
+		    match = m;		// pick worst match
+	    }
+	}
+    }
+#endif
+
     // Loop through the function parameters
     for (i = 0; i < nfparams; i++)
     {
@@ -982,7 +1031,7 @@
 		}
 	    }
 	    else
-	    {	oded = tp->defaultArg(paramscope);
+	    {	oded = tp->defaultArg(loc, paramscope);
 		if (!oded)
 		    goto Lnomatch;
 	    }
@@ -991,6 +1040,25 @@
 	}
     }
 
+#if DMDV2
+    if (constraint)
+    {	/* Check to see if constraint is satisfied.
+	 */
+	Expression *e = constraint->syntaxCopy();
+	paramscope->flags |= SCOPEstaticif;
+	e = e->semantic(paramscope);
+	e = e->optimize(WANTvalue | WANTinterpret);
+        if (e->isBool(TRUE))
+            ;
+        else if (e->isBool(FALSE))
+            goto Lnomatch;
+        else
+        {
+            e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars());
+        }
+    }
+#endif
+
 #if 0
     for (i = 0; i < dedargs->dim; i++)
     {	Type *t = (Type *)dedargs->data[i];
@@ -1096,11 +1164,13 @@
  *	sc		instantiation scope
  *	loc		instantiation location
  *	targsi		initial list of template arguments
+ *	ethis		if !NULL, the 'this' pointer argument
  *	fargs		arguments to function
+ *	flags		1: do not issue error message on no match, just return NULL
  */
 
 FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
-	Objects *targsi, Expressions *fargs)
+	Objects *targsi, Expression *ethis, Expressions *fargs, int flags)
 {
     MATCH m_best = MATCHnomatch;
     TemplateDeclaration *td_ambig = NULL;
@@ -1142,7 +1212,7 @@
 	MATCH m;
 	Objects dedargs;
 
-	m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs);
+	m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs);
 	//printf("deduceFunctionTemplateMatch = %d\n", m);
 	if (!m)			// if no match
 	    continue;
@@ -1207,14 +1277,26 @@
 
   Lerror:
     {
+	HdrGenState hgs;
+
+	OutBuffer bufa;
+	Objects *args = targsi;
+	if (args)
+	{   for (int i = 0; i < args->dim; i++)
+	    {
+		if (i)
+		    bufa.writeByte(',');
+		Object *oarg = (Object *)args->data[i];
+		ObjectToCBuffer(&bufa, &hgs, oarg);
+	    }
+	}
+
 	OutBuffer buf;
-	HdrGenState hgs;
-
 	argExpTypesToCBuffer(&buf, fargs, &hgs);
-	error(loc, "cannot deduce template function from argument types (%s)",
-		buf.toChars());
-	return NULL;
+	error(loc, "cannot deduce template function from argument types !(%s)(%s)",
+		bufa.toChars(), buf.toChars());
     }
+    return NULL;
 }
 
 void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
@@ -1237,6 +1319,13 @@
 	tp->toCBuffer(buf, hgs);
     }
     buf->writeByte(')');
+#if DMDV2
+    if (constraint)
+    {	buf->writestring(" if (");
+	constraint->toCBuffer(buf, hgs);
+	buf->writeByte(')');
+    }
+#endif
 
     if (hgs->hdrgen)
     {
@@ -1271,6 +1360,13 @@
 	tp->toCBuffer(&buf, &hgs);
     }
     buf.writeByte(')');
+#if DMDV2
+    if (constraint)
+    {	buf.writestring(" if (");
+	constraint->toCBuffer(&buf, &hgs);
+	buf.writeByte(')');
+    }
+#endif
     buf.writeByte(0);
     return (char *)buf.extractData();
 }
@@ -1323,9 +1419,11 @@
 MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
 	Objects *dedtypes)
 {
-    //printf("Type::deduceType()\n");
-    //printf("\tthis   = %d, ", ty); print();
-    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#if 0
+    printf("Type::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
     if (!tparam)
 	goto Lnomatch;
 
@@ -2027,7 +2125,7 @@
 	oarg = (Object *)tiargs->data[i];
     else
     {	// Get default argument instead
-	oarg = defaultArg(sc);
+	oarg = defaultArg(loc, sc);
 	if (!oarg)
 	{   assert(i < dedtypes->dim);
 	    // It might have already been deduced
@@ -2141,7 +2239,7 @@
 }
 
 
-Object *TemplateTypeParameter::defaultArg(Scope *sc)
+Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc)
 {
     Type *t;
 
@@ -2271,7 +2369,7 @@
 	oarg = (Object *)tiargs->data[i];
     else
     {	// Get default argument instead
-	oarg = defaultArg(sc);
+	oarg = defaultArg(loc, sc);
 	if (!oarg)
 	{   assert(i < dedtypes->dim);
 	    // It might have already been deduced
@@ -2357,7 +2455,7 @@
 }
 
 
-Object *TemplateAliasParameter::defaultArg(Scope *sc)
+Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc)
 {
     Dsymbol *s = NULL;
 
@@ -2485,7 +2583,7 @@
 	oarg = (Object *)tiargs->data[i];
     else
     {	// Get default argument instead
-	oarg = defaultArg(sc);
+	oarg = defaultArg(loc, sc);
 	if (!oarg)
 	{   assert(i < dedtypes->dim);
 	    // It might have already been deduced
@@ -2602,7 +2700,7 @@
 }
 
 
-Object *TemplateValueParameter::defaultArg(Scope *sc)
+Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc)
 {
     Expression *e = defaultValue;
     if (e)
@@ -2748,7 +2846,7 @@
 }
 
 
-Object *TemplateTupleParameter::defaultArg(Scope *sc)
+Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc)
 {
     return NULL;
 }
@@ -2778,6 +2876,10 @@
     this->tinst = NULL;
 }
 
+/*****************
+ * This constructor is only called when we figured out which function
+ * template to instantiate.
+ */
 
 TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
     : ScopeDsymbol(NULL)
@@ -2830,7 +2932,6 @@
 Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
 {
     TemplateInstance *ti;
-    int i;
 
     if (s)
 	ti = (TemplateInstance *)s;
@@ -2896,7 +2997,9 @@
     }
     else
     {
-	// Run semantic on each argument, place results in tiargs[]
+	/* Run semantic on each argument, place results in tiargs[]
+	 * (if we havetempdecl, then tiargs is already evaluated)
+	 */
 	semanticTiargs(sc);
 
 	tempdecl = findTemplateDeclaration(sc);
@@ -2974,12 +3077,26 @@
 #if 1
     int dosemantic3 = 0;
     {	Array *a;
-	int i;
-
-	if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin())
+
+	Scope *scx = sc;
+#if 0
+	for (scx = sc; scx; scx = scx->enclosing)
+	    if (scx->scopesym)
+		break;
+#endif
+
+	//if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
+	if (scx && scx->scopesym &&
+	    scx->scopesym->members && !scx->scopesym->isTemplateMixin() &&
+	    /* The following test should really be if scx->module recursively
+	     * imports itself. Because if it does, see bugzilla 2500.
+	     */
+	    //scx->module == tempdecl->getModule()
+	    !scx->module->imports(scx->module)
+	   )
 	{
-	    //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
-	    a = sc->scopesym->members;
+	    //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
+	    a = scx->scopesym->members;
 	}
 	else
 	{   Module *m = sc->module->importedFrom;
@@ -3395,19 +3512,15 @@
 	    return NULL;
 	}
 	m = td->matchWithInstance(this, &dedtypes, 0);
-	//printf("m = %d\n", m);
+	//printf("matchWithInstance = %d\n", m);
 	if (!m)			// no match at all
 	    continue;
 
-#if 1
 	if (m < m_best)
 	    goto Ltd_best;
 	if (m > m_best)
 	    goto Ltd;
-#else
-	if (!m_best)
-	    goto Ltd;
-#endif
+
 	{
 	// Disambiguate by picking the most specialized TemplateDeclaration
 	int c1 = td->leastAsSpecialized(td_best);
@@ -3656,6 +3769,7 @@
     buf.writeByte('Z');
     id = buf.toChars();
     buf.data = NULL;
+    //printf("\tgenIdent = %s\n", id);
     return new Identifier(id, TOKidentifier);
 }
 
@@ -3672,7 +3786,7 @@
     {
 	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
 	//Object *o = (Object *)tiargs->data[i];
-	Object *o = (Object *)tdtypes.data[i];
+	Object *o = (Object *)tdtypes.data[i];		// initializer for tp
 
 	//printf("\ttdtypes[%d] = %p\n", i, o);
 	tempdecl->declareParameter(scope, tp, o);
--- a/dmd/template.h	Tue Jan 06 15:54:48 2009 +0100
+++ b/dmd/template.h	Tue Jan 06 16:33:51 2009 +0100
@@ -1,6 +1,6 @@
 
 // Compiler implementation of the D programming language
-// Copyright (c) 1999-2006 by Digital Mars
+// Copyright (c) 1999-2008 by Digital Mars
 // All Rights Reserved
 // written by Walter Bright
 // http://www.digitalmars.com
@@ -54,7 +54,9 @@
     TemplateParameters *parameters;	// array of TemplateParameter's
 
     TemplateParameters *origParameters;	// originals for Ddoc
-
+#if DMDV2
+    Expression *constraint;
+#endif
     Array instances;			// array of TemplateInstance's
 
     TemplateDeclaration *overnext;	// next overloaded TemplateDeclaration
@@ -63,7 +65,11 @@
     Scope *scope;
     Dsymbol *onemember;		// if !=NULL then one member of this template
 
-    TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs);
+    TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters,
+#if DMDV2
+	Expression *constraint,
+#endif
+	Array *decldefs);
     Dsymbol *syntaxCopy(Dsymbol *);
     void semantic(Scope *sc);
     int overloadInsert(Dsymbol *s);
@@ -77,8 +83,8 @@
     MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag);
     int leastAsSpecialized(TemplateDeclaration *td2);
 
-    MATCH deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, Objects *dedargs);
-    FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs);
+    MATCH deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs);
+    FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0);
     void declareParameter(Scope *sc, TemplateParameter *tp, Object *o);
 
     TemplateDeclaration *isTemplateDeclaration() { return this; }
@@ -112,6 +118,9 @@
     virtual TemplateTypeParameter  *isTemplateTypeParameter();
     virtual TemplateValueParameter *isTemplateValueParameter();
     virtual TemplateAliasParameter *isTemplateAliasParameter();
+#if DMDV2
+    virtual TemplateThisParameter *isTemplateThisParameter();
+#endif
     virtual TemplateTupleParameter *isTemplateTupleParameter();
 
     virtual TemplateParameter *syntaxCopy() = 0;
@@ -120,7 +129,7 @@
     virtual void print(Object *oarg, Object *oded) = 0;
     virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
     virtual Object *specialization() = 0;
-    virtual Object *defaultArg(Scope *sc) = 0;
+    virtual Object *defaultArg(Loc loc, Scope *sc) = 0;
 
     /* If TemplateParameter's match as far as overloading goes.
      */
@@ -152,7 +161,7 @@
     void print(Object *oarg, Object *oded);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Object *specialization();
-    Object *defaultArg(Scope *sc);
+    Object *defaultArg(Loc loc, Scope *sc);
     int overloadMatch(TemplateParameter *);
     MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
     void *dummyArg();
@@ -196,7 +205,7 @@
     void print(Object *oarg, Object *oded);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Object *specialization();
-    Object *defaultArg(Scope *sc);
+    Object *defaultArg(Loc loc, Scope *sc);
     int overloadMatch(TemplateParameter *);
     MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
     void *dummyArg();
@@ -224,7 +233,7 @@
     void print(Object *oarg, Object *oded);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Object *specialization();
-    Object *defaultArg(Scope *sc);
+    Object *defaultArg(Loc loc, Scope *sc);
     int overloadMatch(TemplateParameter *);
     MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
     void *dummyArg();
@@ -245,7 +254,7 @@
     void print(Object *oarg, Object *oded);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     Object *specialization();
-    Object *defaultArg(Scope *sc);
+    Object *defaultArg(Loc loc, Scope *sc);
     int overloadMatch(TemplateParameter *);
     MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
     void *dummyArg();
--- a/gen/statements.cpp	Tue Jan 06 15:54:48 2009 +0100
+++ b/gen/statements.cpp	Tue Jan 06 16:33:51 2009 +0100
@@ -1375,7 +1375,7 @@
         statement->toIR(p);
 
         // no point in a unreachable barrier, terminating statements must insert this themselves.
-        if (statement->fallOffEnd())
+        if (statement->blockExit() & BEfallthru)
         {
             // store-load
             DtoMemoryBarrier(false, false, true, false);