changeset 758:f04dde6e882c

Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:38:48 +0100
parents 2c730d530c98
children d3eb054172f9
files CMakeLists.txt dmd/mtype.h dmd2/access.c dmd2/aggregate.h dmd2/array.c dmd2/arrayop.c dmd2/arraytypes.h dmd2/artistic.txt dmd2/attrib.c dmd2/attrib.h dmd2/builtin.c dmd2/cast.c dmd2/class.c dmd2/clone.c dmd2/complex_t.h dmd2/cond.c dmd2/cond.h dmd2/constfold.c dmd2/dchar.c dmd2/dchar.h dmd2/declaration.c dmd2/declaration.h dmd2/delegatize.c dmd2/doc.c dmd2/doc.h dmd2/dsymbol.c dmd2/dsymbol.h dmd2/dump.c dmd2/e2ir.c.nolink dmd2/entity.c dmd2/enum.c dmd2/enum.h dmd2/expression.c dmd2/expression.h dmd2/func.c dmd2/gnuc.c dmd2/gnuc.h dmd2/gpl.txt dmd2/hdrgen.c dmd2/hdrgen.h dmd2/html.c dmd2/html.h dmd2/id.c dmd2/id.h dmd2/identifier.c dmd2/identifier.h dmd2/idgen.c dmd2/impcnvgen.c dmd2/impcnvtab.c dmd2/import.c dmd2/import.h dmd2/inifile.c dmd2/init.c dmd2/init.h dmd2/inline.c dmd2/interpret.c dmd2/lexer.c dmd2/lexer.h dmd2/link.c.nolink dmd2/lstring.c dmd2/lstring.h dmd2/macro.c dmd2/macro.h dmd2/man.c dmd2/mangle.c dmd2/mars.c dmd2/mars.h dmd2/mem.c dmd2/mem.h dmd2/module.c dmd2/module.h dmd2/mtype.c dmd2/mtype.h dmd2/opover.c dmd2/optimize.c dmd2/parse.c dmd2/parse.h dmd2/port.h dmd2/readme.txt dmd2/root.c dmd2/root.h dmd2/scope.c dmd2/scope.h dmd2/statement.c dmd2/statement.h dmd2/staticassert.c dmd2/staticassert.h dmd2/stringtable.c dmd2/stringtable.h dmd2/struct.c dmd2/template.c dmd2/template.h dmd2/total.h dmd2/traits.c dmd2/unialpha.c dmd2/utf.c dmd2/utf.h dmd2/version.c dmd2/version.h gen/arrays.cpp gen/asmstmt.cpp gen/classes.cpp gen/functions.cpp gen/llvmhelpers.cpp gen/statements.cpp gen/tocall.cpp gen/tocsym.cpp gen/toir.cpp gen/tollvm.cpp gen/toobj.cpp gen/typinf.cpp ir/irlandingpad.cpp llvmdc.kdevelop llvmdc.kdevelop.filelist premake.lua
diffstat 115 files changed, 83772 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Mon Nov 10 20:55:24 2008 +0100
+++ b/CMakeLists.txt	Tue Nov 11 01:38:48 2008 +0100
@@ -39,19 +39,32 @@
 # get llvm's install dir. a little hackish, we could do something like llvm-config --prefix, but this does as well
 string(REPLACE "/bin/llvm-config" "" LLVM_INSTDIR ${LLVM_CONFIG})
 
+set(D_VERSION 1 CACHE STRING "D language version")
+if(D_VERSION EQUAL 1)
+	set(DMDFE_PATH dmd)
+	set(LDC_EXE ldc)
+	add_definitions(-DDMDV1)
+elseif(D_VERSION EQUAL 2)
+	set(DMDFE_PATH dmd2)
+	set(LDC_EXE ldc2)
+	add_definitions(-DDMDV2)
+else(D_VERSION EQUAL 1)
+	message(FATAL_ERROR "unsupported D version")
+endif(D_VERSION EQUAL 1)
+
 file(MAKE_DIRECTORY
 	${PROJECT_BINARY_DIR}/bin
-	${PROJECT_BINARY_DIR}/dmd
+	${PROJECT_BINARY_DIR}/${DMDFE_PATH}
 )
 
 # idgen and impcnvgen
 set_source_files_properties(
-	dmd/idgen.c
-	dmd/impcnvgen.c
+	${DMDFE_PATH}/idgen.c
+	${DMDFE_PATH}/impcnvgen.c
 	PROPERTIES LANGUAGE CXX
 )
-add_executable(idgen dmd/idgen.c)
-add_executable(impcnvgen dmd/impcnvgen.c)
+add_executable(idgen ${DMDFE_PATH}/idgen.c)
+add_executable(impcnvgen ${DMDFE_PATH}/impcnvgen.c)
 # cmake 2.4
 set_target_properties(
 	idgen impcnvgen PROPERTIES
@@ -62,42 +75,42 @@
 # 
 add_custom_command(
 	OUTPUT
-		${PROJECT_BINARY_DIR}/dmd/id.c
-		${PROJECT_BINARY_DIR}/dmd/id.h
+		${PROJECT_BINARY_DIR}/${DMDFE_PATH}/id.c
+		${PROJECT_BINARY_DIR}/${DMDFE_PATH}/id.h
 	# 2.4
 	COMMAND ${IDGEN_LOC}
 	#COMMAND idgen
-	WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/dmd
+	WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/${DMDFE_PATH}
 	DEPENDS idgen
 )
 add_custom_command(
-	OUTPUT ${PROJECT_BINARY_DIR}/dmd/impcnvtab.c
+	OUTPUT ${PROJECT_BINARY_DIR}/${DMDFE_PATH}/impcnvtab.c
 	# 2.4
 	COMMAND ${IMPCNVGEN_LOC}
 	#COMMAND impcnvgen 
-	WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/dmd
+	WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/${DMDFE_PATH}
 	DEPENDS impcnvgen
 )
 set(LDC_GENERATED
-	${PROJECT_BINARY_DIR}/dmd/id.c
-	${PROJECT_BINARY_DIR}/dmd/id.h
-	${PROJECT_BINARY_DIR}/dmd/impcnvtab.c
+	${PROJECT_BINARY_DIR}/${DMDFE_PATH}/id.c
+	${PROJECT_BINARY_DIR}/${DMDFE_PATH}/id.h
+	${PROJECT_BINARY_DIR}/${DMDFE_PATH}/impcnvtab.c
 )
 # idgen and impcnvgen done
 
 set(DEFAULT_TARGET ${HOST_TARGET} CACHE STRING "default target")
 
-include_directories(. dmd ${PROJECT_BINARY_DIR}/dmd ${LLVM_INSTDIR}/include)
+include_directories(. ${DMDFE_PATH} ${PROJECT_BINARY_DIR}/${DMDFE_PATH} ${LLVM_INSTDIR}/include)
 
-file(GLOB FE_SRC dmd/*.c)
+file(GLOB FE_SRC ${DMDFE_PATH}/*.c)
 file(GLOB GEN_SRC gen/*.cpp)
 file(GLOB IR_SRC ir/*.cpp)
 # exclude idgen and impcnvgen and generated sources, just in case
 list(REMOVE_ITEM FE_SRC
-	${PROJECT_SOURCE_DIR}/dmd/idgen.c
-	${PROJECT_SOURCE_DIR}/dmd/impcnvgen.c
-	${PROJECT_SOURCE_DIR}/dmd/id.c
-	${PROJECT_SOURCE_DIR}/dmd/impcnvtab.c
+	${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/idgen.c
+	${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/impcnvgen.c
+	${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/id.c
+	${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/impcnvtab.c
 )
 set(LDC_SOURCE_FILES
 	${LDC_GENERATED}
@@ -115,7 +128,6 @@
 	-D_DH
 	-DOPAQUE_VTBLS
 	-DUSE_BOEHM_GC=0
-	-DDMDV1
 	-DX86_REVERSE_PARAMS
 	-DX86_PASS_IN_EAX
 )
@@ -131,26 +143,26 @@
 	add_definitions(-DDEFAULT_TARGET_TRIPLE="${DEFAULT_TARGET}")
 endif(CMAKE_MINOR_VERSION LESS 6)
 
-add_executable(ldc ${LDC_SOURCE_FILES})
+add_executable(${LDC_EXE} ${LDC_SOURCE_FILES})
 
 set_target_properties(
-	ldc PROPERTIES
+	${LDC_EXE} PROPERTIES
 	RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
-	COMPILE_FLAGS "${LLVM_CXXFLAGS} -Wno-deprecated"
+	COMPILE_FLAGS "${LLVM_CXXFLAGS} -Wno-deprecated -Wno-write-strings"
 )
 
 # LDFLAGS should actually be in target property LINK_FLAGS, but this works, and gets around linking problems
-target_link_libraries(ldc "${LLVM_LDFLAGS} ${LLVM_LIBS}")
+target_link_libraries(${LDC_EXE} "${LLVM_LDFLAGS} ${LLVM_LIBS}")
 if(WIN32)
-	target_link_libraries(ldc psapi)
+	target_link_libraries(${LDC_EXE} psapi)
 	#set(CONF_SUFFIX ini)
 endif(WIN32)
 
 # cmake pre 2.6 doesn't support the RUNTIME_OUTPUT_DIRECTORY target property
 if(CMAKE_MINOR_VERSION LESS 6)
-	get_target_property(LDC_LOC ldc LOCATION)
+	get_target_property(LDC_LOC ${LDC_EXE} LOCATION)
 	add_custom_command(
-		TARGET ldc
+		TARGET ${LDC_EXE}
 		POST_BUILD
 		COMMAND ${CMAKE_COMMAND} -E copy ${LDC_LOC} ${PROJECT_BINARY_DIR}/bin/
 		COMMAND ${CMAKE_COMMAND} -E remove ${LDC_LOC}
--- a/dmd/mtype.h	Mon Nov 10 20:55:24 2008 +0100
+++ b/dmd/mtype.h	Tue Nov 11 01:38:48 2008 +0100
@@ -368,7 +368,7 @@
     int hasPointers();
 
     // Back end
-    Symbol *aaGetSymbol(char *func, int flags);
+    Symbol *aaGetSymbol(const char *func, int flags);
 
     type *toCtype();
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/access.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,424 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "scope.h"
+#include "id.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "module.h"
+
+#define LOG 0
+
+/* Code to do access checks
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s);
+
+/****************************************
+ * Return PROT access for Dsymbol smember in this declaration.
+ */
+
+enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
+{
+    return PROTpublic;
+}
+
+enum PROT StructDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else if (smember->isDeclaration()->isStatic())
+    {
+	access_ret = smember->prot();
+    }
+    return access_ret;
+}
+
+enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else
+    {
+	enum PROT access;
+	int i;
+
+	if (smember->isDeclaration()->isStatic())
+	{
+	    access_ret = smember->prot();
+	}
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{   BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    access = b->base->getAccess(smember);
+	    switch (access)
+	    {
+		case PROTnone:
+		    break;
+
+		case PROTprivate:
+		    access = PROTnone;	// private members of base class not accessible
+		    break;
+
+		case PROTpackage:
+		case PROTprotected:
+		case PROTpublic:
+		case PROTexport:
+		    // If access is to be tightened
+		    if (b->protection < access)
+			access = b->protection;
+
+		    // Pick path with loosest access
+		    if (access > access_ret)
+			access_ret = access;
+		    break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+#if LOG
+    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
+	toChars(), smember->toChars(), access_ret);
+#endif
+    return access_ret;
+}
+
+/********************************************************
+ * Helper function for ClassDeclaration::accessCheck()
+ * Returns:
+ *	0	no access
+ * 	1	access
+ */
+
+static int accessCheckX(
+	Dsymbol *smember,
+	Dsymbol *sfunc,
+	AggregateDeclaration *dthis,
+	AggregateDeclaration *cdscope)
+{
+    assert(dthis);
+
+#if 0
+    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
+	dthis->toChars(), smember->toChars(),
+	sfunc ? sfunc->toChars() : "NULL",
+	cdscope ? cdscope->toChars() : "NULL");
+#endif
+    if (dthis->hasPrivateAccess(sfunc) ||
+	dthis->isFriendOf(cdscope))
+    {
+	if (smember->toParent() == dthis)
+	    return 1;
+	else
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+		    enum PROT access;
+
+		    access = b->base->getAccess(smember);
+		    if (access >= PROTprotected ||
+			accessCheckX(smember, sfunc, b->base, cdscope)
+		       )
+			return 1;
+
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (smember->toParent() != dthis)
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+
+		    if (accessCheckX(smember, sfunc, b->base, cdscope))
+			return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ */
+
+void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
+{
+    int result;
+
+    FuncDeclaration *f = sc->func;
+    AggregateDeclaration *cdscope = sc->getStructClassScope();
+    enum PROT access;
+
+#if LOG
+    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
+	toChars(), smember->toChars(),
+	f ? f->toChars() : NULL,
+	cdscope ? cdscope->toChars() : NULL);
+#endif
+
+    Dsymbol *smemberparent = smember->toParent();
+    if (!smemberparent || !smemberparent->isAggregateDeclaration())
+    {
+#if LOG
+	printf("not an aggregate member\n");
+#endif
+	return;				// then it is accessible
+    }
+
+    // BUG: should enable this check
+    //assert(smember->parent->isBaseOf(this, NULL));
+
+    if (smemberparent == this)
+    {	enum PROT access = smember->prot();
+
+	result = access >= PROTpublic ||
+		hasPrivateAccess(f) ||
+		isFriendOf(cdscope) ||
+		(access == PROTpackage && hasPackageAccess(sc, this));
+#if LOG
+	printf("result1 = %d\n", result);
+#endif
+    }
+    else if ((access = this->getAccess(smember)) >= PROTpublic)
+    {
+	result = 1;
+#if LOG
+	printf("result2 = %d\n", result);
+#endif
+    }
+    else if (access == PROTpackage && hasPackageAccess(sc, this))
+    {
+	result = 1;
+#if LOG
+	printf("result3 = %d\n", result);
+#endif
+    }
+    else
+    {
+	result = accessCheckX(smember, f, this, cdscope);
+#if LOG
+	printf("result4 = %d\n", result);
+#endif
+    }
+    if (!result)
+    {
+	error(loc, "member %s is not accessible", smember->toChars());
+halt();
+    }
+}
+
+/****************************************   
+ * Determine if this is the same or friend of cd.
+ */
+
+int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
+{
+#if LOG
+    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
+#endif
+    if (this == cd)
+	return 1;
+
+    // Friends if both are in the same module
+    //if (toParent() == cd->toParent())
+    if (cd && getModule() == cd->getModule())
+    {
+#if LOG
+	printf("\tin same module\n");
+#endif
+	return 1;
+    }
+
+#if LOG
+    printf("\tnot friend\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+#if LOG
+    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
+#endif
+
+    for (; s; s = s->parent)
+    {
+	if (s->isPackage() && !s->isModule())
+	    break;
+    }
+#if LOG
+    if (s)
+	printf("\tthis is in package '%s'\n", s->toChars());
+#endif
+
+    if (s && s == sc->module->parent)
+    {
+#if LOG
+	printf("\ts is in same package as sc\n");
+#endif
+	return 1;
+    }
+
+
+#if LOG
+    printf("\tno package access\n");
+#endif
+    return 0;
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+
+int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
+{
+    if (smember)
+    {	AggregateDeclaration *cd = NULL;
+	Dsymbol *smemberparent = smember->toParent();
+	if (smemberparent)
+	    cd = smemberparent->isAggregateDeclaration();
+
+#if LOG
+	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
+		toChars(), smember->toChars());
+#endif
+
+	if (this == cd)		// smember is a member of this class
+	{
+#if LOG
+	    printf("\tyes 1\n");
+#endif
+	    return 1;		// so we get private access
+	}
+
+	// If both are members of the same module, grant access
+	while (1)
+	{   Dsymbol *sp = smember->toParent();
+	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
+		smember = sp;
+	    else
+		break;
+	}
+	if (!cd && toParent() == smember->toParent())
+	{
+#if LOG
+	    printf("\tyes 2\n");
+#endif
+	    return 1;
+	}
+	if (!cd && getModule() == smember->getModule())
+	{
+#if LOG
+	    printf("\tyes 3\n");
+#endif
+	    return 1;
+	}
+    }
+#if LOG
+    printf("\tno\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ */
+
+void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+#if LOG
+    if (e)
+    {	printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
+	printf("\te->type = %s\n", e->type->toChars());
+    }
+    else
+    {
+	//printf("accessCheck(%s)\n", d->toChars());
+    }
+#endif
+    if (!e)
+    {
+	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
+	    d->prot() == PROTpackage && !hasPackageAccess(sc, d))
+
+	    error(loc, "%s %s.%s is not accessible from %s",
+		d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
+    }
+    else if (e->type->ty == Tclass)
+    {   // Do access check
+	ClassDeclaration *cd;
+
+	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+#if 1
+	if (e->op == TOKsuper)
+	{   ClassDeclaration *cd2;
+
+	    cd2 = sc->func->toParent()->isClassDeclaration();
+	    if (cd2)
+		cd = cd2;
+	}
+#endif
+	cd->accessCheck(loc, sc, d);
+    }
+    else if (e->type->ty == Tstruct)
+    {   // Do access check
+	StructDeclaration *cd;
+
+	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+	cd->accessCheck(loc, sc, d);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/aggregate.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,296 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_AGGREGATE_H
+#define DMD_AGGREGATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+#include <vector>
+#include <set>
+#include <map>
+
+struct Identifier;
+struct Type;
+struct TypeFunction;
+struct Expression;
+struct FuncDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct InvariantDeclaration;
+struct NewDeclaration;
+struct DeleteDeclaration;
+struct InterfaceDeclaration;
+struct ClassInfoDeclaration;
+struct VarDeclaration;
+struct dt_t;
+
+namespace llvm
+{
+    class Type;
+    class Value;
+    class Constant;
+    class ConstantStruct;
+    class GlobalVariable;
+}
+struct DUnion;
+
+struct AggregateDeclaration : ScopeDsymbol
+{
+    Type *type;
+    unsigned storage_class;
+    enum PROT protection;
+    Type *handle;		// 'this' type
+    unsigned structsize;	// size of struct
+    unsigned alignsize;		// size of struct for alignment purposes
+    unsigned structalign;	// struct member alignment in effect
+    int hasUnions;		// set if aggregate has overlapping fields
+    Array fields;		// VarDeclaration fields
+    unsigned sizeok;		// set when structsize contains valid data
+				// 0: no size
+				// 1: size is correct
+				// 2: cannot determine size; fwd referenced
+    int isdeprecated;		// !=0 if deprecated
+    Scope *scope;		// !=NULL means context to use
+
+    // Special member functions
+    InvariantDeclaration *inv;		// invariant
+    NewDeclaration *aggNew;		// allocator
+    DeleteDeclaration *aggDelete;	// deallocator
+
+#if DMDV2
+    CtorDeclaration *ctor;
+    CtorDeclaration *defaultCtor;	// default constructor
+#endif
+
+    FuncDeclarations dtors;	// Array of destructors
+    FuncDeclaration *dtor;	// aggregate destructor
+
+#ifdef IN_GCC
+    Array methods;              // flat list of all methods for debug information
+#endif
+
+    AggregateDeclaration(Loc loc, Identifier *id);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    unsigned size(Loc loc);
+    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
+    Type *getType();
+    void addField(Scope *sc, VarDeclaration *v);
+    int isDeprecated();		// is aggregate deprecated?
+    FuncDeclaration *buildDtor(Scope *sc);
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    // For access checking
+    virtual PROT getAccess(Dsymbol *smember);	// determine access to smember
+    int isFriendOf(AggregateDeclaration *cd);
+    int hasPrivateAccess(Dsymbol *smember);	// does smember have private access to members of this class?
+    void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
+
+    enum PROT prot();
+
+    // Back end
+    Symbol *stag;		// tag symbol for debug data
+    Symbol *sinit;
+    Symbol *toInitializer();
+
+    AggregateDeclaration *isAggregateDeclaration() { return this; }
+};
+
+struct AnonymousAggregateDeclaration : AggregateDeclaration
+{
+    AnonymousAggregateDeclaration()
+	: AggregateDeclaration(0, NULL)
+    {
+    }
+
+    AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
+};
+
+struct StructDeclaration : AggregateDeclaration
+{
+    int zeroInit;		// !=0 if initialize with 0 fill
+#if DMDV2
+    int hasIdentityAssign;	// !=0 if has identity opAssign
+    FuncDeclaration *cpctor;	// generated copy-constructor, if any
+
+    FuncDeclarations postblits;	// Array of postblit functions
+    FuncDeclaration *postblit;	// aggregate postblit
+#endif
+
+    StructDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *mangle();
+    const char *kind();
+    int needOpAssign();
+    FuncDeclaration *buildOpAssign(Scope *sc);
+    FuncDeclaration *buildPostBlit(Scope *sc);
+    FuncDeclaration *buildCpCtor(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void toObjFile(int multiobj);			// compile to .obj file
+    void toDt(dt_t **pdt);
+    void toDebug();			// to symbolic debug info
+
+    StructDeclaration *isStructDeclaration() { return this; }
+};
+
+struct UnionDeclaration : StructDeclaration
+{
+    UnionDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    const char *kind();
+
+    UnionDeclaration *isUnionDeclaration() { return this; }
+};
+
+struct BaseClass
+{
+    Type *type;				// (before semantic processing)
+    enum PROT protection;		// protection for the base interface
+
+    ClassDeclaration *base;
+    int offset;				// 'this' pointer offset
+    Array vtbl;				// for interfaces: Array of FuncDeclaration's
+					// making up the vtbl[]
+
+    int baseInterfaces_dim;
+    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
+					// are a copy of the InterfaceDeclaration::interfaces
+
+    BaseClass();
+    BaseClass(Type *type, enum PROT protection);
+
+    int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance);
+    void copyBaseInterfaces(BaseClasses *);
+};
+
+#if DMDV2
+#define CLASSINFO_SIZE 	(0x3C+16)	// value of ClassInfo.size
+#else
+#define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
+#endif
+
+struct ClassDeclaration : AggregateDeclaration
+{
+    static ClassDeclaration *object;
+    static ClassDeclaration *classinfo;
+
+    ClassDeclaration *baseClass;	// NULL only if this is Object
+    FuncDeclaration *staticCtor;
+    FuncDeclaration *staticDtor;
+    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
+    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]
+
+    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
+					// rest are Interface's
+
+    int interfaces_dim;
+    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
+					// (does not include baseClass)
+
+    BaseClasses *vtblInterfaces;	// array of base interfaces that have
+					// their own vtbl[]
+
+    ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this ClassDeclaration
+    int com;				// !=0 if this is a COM class (meaning
+					// it derives from IUnknown)
+    int isauto;				// !=0 if this is an auto class
+    int isabstract;			// !=0 if abstract class
+
+    int isnested;			// !=0 if is nested
+    VarDeclaration *vthis;		// 'this' parameter if this class is nested
+
+    int inuse;				// to prevent recursive attempts
+
+    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isBaseOf2(ClassDeclaration *cd);
+
+    #define OFFSET_RUNTIME 0x76543210
+    virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
+
+    Dsymbol *search(Loc, Identifier *ident, int flags);
+#if DMDV2
+    int isFuncHidden(FuncDeclaration *fd);
+#endif
+    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+    void interfaceSemantic(Scope *sc);
+    int isNested();
+    int isCOMclass();
+    virtual int isCOMinterface();
+#if DMDV2
+    virtual int isCPPinterface();
+#endif
+    int isAbstract();
+    virtual int vtblOffset();
+    const char *kind();
+    char *mangle();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void addLocalClass(ClassDeclarations *);
+
+    // Back end
+    void toObjFile(int multiobj);			// compile to .obj file
+    void toDebug();
+    unsigned baseVtblOffset(BaseClass *bc);
+    Symbol *toSymbol();
+    Symbol *toVtblSymbol();
+    void toDt(dt_t **pdt);
+    void toDt2(dt_t **pdt, ClassDeclaration *cd);
+
+    Symbol *vtblsym;
+
+    // llvm
+    void offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result);
+
+    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+};
+
+struct InterfaceDeclaration : ClassDeclaration
+{
+#if DMDV2
+    int cpp;				// !=0 if this is a C++ interface
+#endif
+    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int isBaseOf(ClassDeclaration *cd, int *poffset);
+    int isBaseOf(BaseClass *bc, int *poffset);
+    const char *kind();
+    int vtblOffset();
+#if DMDV2
+    int isCPPinterface();
+#endif
+    virtual int isCOMinterface();
+
+    void toObjFile(int multiobj);			// compile to .obj file
+    Symbol *toSymbol();
+
+    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+};
+
+#endif /* DMD_AGGREGATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/array.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,220 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#if _MSC_VER || __MINGW32__
+#include <malloc.h>
+#endif
+
+#if IN_GCC
+#include "gdc_alloca.h"
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "port.h"
+#include "root.h"
+#include "dchar.h"
+#include "mem.h"
+
+
+/********************************* Array ****************************/
+
+Array::Array()
+{
+    data = NULL;
+    dim = 0;
+    allocdim = 0;
+}
+
+Array::~Array()
+{
+    mem.free(data);
+}
+
+void Array::mark()
+{   unsigned u;
+
+    mem.mark(data);
+    for (u = 0; u < dim; u++)
+	mem.mark(data[u]);	// BUG: what if arrays of Object's?
+}
+
+void Array::reserve(unsigned nentries)
+{
+    //printf("Array::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (allocdim - dim < nentries)
+    {
+	allocdim = dim + nentries;
+	data = (void **)mem.realloc(data, allocdim * sizeof(*data));
+    }
+}
+
+void Array::setDim(unsigned newdim)
+{
+    if (dim < newdim)
+    {
+	reserve(newdim - dim);
+    }
+    dim = newdim;
+}
+
+void Array::fixDim()
+{
+    if (dim != allocdim)
+    {	data = (void **)mem.realloc(data, dim * sizeof(*data));
+	allocdim = dim;
+    }
+}
+
+void Array::push(void *ptr)
+{
+    reserve(1);
+    data[dim++] = ptr;
+}
+
+void *Array::pop()
+{
+    return data[--dim];
+}
+
+void Array::shift(void *ptr)
+{
+    reserve(1);
+    memmove(data + 1, data, dim * sizeof(*data));
+    data[0] = ptr;
+    dim++;
+}
+
+void Array::insert(unsigned index, void *ptr)
+{
+    reserve(1);
+    memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
+    data[index] = ptr;
+    dim++;
+}
+
+
+void Array::insert(unsigned index, Array *a)
+{
+    if (a)
+    {	unsigned d;
+
+	d = a->dim;
+	reserve(d);
+	if (dim != index)
+	    memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
+	memcpy(data + index, a->data, d * sizeof(*data));
+	dim += d;
+    }
+}
+
+
+/***********************************
+ * Append array a to this array.
+ */
+
+void Array::append(Array *a)
+{
+    insert(dim, a);
+}
+
+void Array::remove(unsigned i)
+{
+    memmove(data + i, data + i + 1, (dim - i) * sizeof(data[0]));
+    dim--;
+}
+
+char *Array::toChars()
+{
+    unsigned len;
+    unsigned u;
+    char **buf;
+    char *str;
+    char *p;
+
+    buf = (char **)alloca(dim * sizeof(char *));
+    len = 2;
+    for (u = 0; u < dim; u++)
+    {
+	buf[u] = ((Object *)data[u])->toChars();
+	len += strlen(buf[u]) + 1;
+    }
+    str = (char *)mem.malloc(len);
+
+    str[0] = '[';
+    p = str + 1;
+    for (u = 0; u < dim; u++)
+    {
+	if (u)
+	    *p++ = ',';
+	len = strlen(buf[u]);
+	memcpy(p,buf[u],len);
+	p += len;
+    }
+    *p++ = ']';
+    *p = 0;
+    return str;
+}
+
+void Array::zero()
+{
+    memset(data,0,dim * sizeof(data[0]));
+}
+
+void *Array::tos()
+{
+    return dim ? data[dim - 1] : NULL;
+}
+
+int
+#if _WIN32
+  __cdecl
+#endif
+	Array_sort_compare(const void *x, const void *y)
+{
+    Object *ox = *(Object **)x;
+    Object *oy = *(Object **)y;
+
+    return ox->compare(oy);
+}
+
+void Array::sort()
+{
+    if (dim)
+    {
+	qsort(data, dim, sizeof(Object *), Array_sort_compare);
+    }
+}
+
+Array *Array::copy()
+{
+    Array *a = new Array();
+
+    a->setDim(dim);
+    memcpy(a->data, data, dim * sizeof(void *));
+    return a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/arrayop.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,494 @@
+
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC  || IN_LLVM
+#include "mem.h"
+#else
+#include "../root/mem.h"
+#endif
+
+#include "stringtable.h"
+
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "scope.h"
+#include "id.h"
+#include "module.h"
+#include "init.h"
+
+
+/***********************************
+ * Construct the array operation expression.
+ */
+
+Expression *BinExp::arrayOp(Scope *sc)
+{
+    Expressions *arguments = new Expressions();
+
+    /* The expression to generate an array operation for is mangled
+     * into a name to use as the array operation function name.
+     * Mangle in the operands and operators in RPN order, and type.
+     */
+    OutBuffer buf;
+    buf.writestring("_array");
+    buildArrayIdent(&buf, arguments);
+    buf.writeByte('_');
+
+    /* Append deco of array element type
+     */
+#if DMDV2
+    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
+#else
+    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
+#endif
+
+    size_t namelen = buf.offset;
+    buf.writeByte(0);
+    char *name = (char *)buf.extractData();
+
+    /* Look up name in hash table
+     */
+    StringValue *sv = sc->module->arrayfuncs.update(name, namelen);
+    FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue;
+    if (!fd)
+    {
+//     /* Some of the array op functions are written as library functions,
+//      * presumably to optimize them with special CPU vector instructions.
+//      * List those library functions here, in alpha order.
+//      */
+//     static const char *libArrayopFuncs[] =
+//     {
+//         "_arrayExpSliceAddass_a",
+//         "_arrayExpSliceAddass_d",       // T[]+=T
+//         "_arrayExpSliceAddass_f",       // T[]+=T
+//         "_arrayExpSliceAddass_g",
+//         "_arrayExpSliceAddass_h",
+//         "_arrayExpSliceAddass_i",
+//         "_arrayExpSliceAddass_k",
+//         "_arrayExpSliceAddass_s",
+//         "_arrayExpSliceAddass_t",
+//         "_arrayExpSliceAddass_u",
+//         "_arrayExpSliceAddass_w",
+// 
+//         "_arrayExpSliceDivass_d",       // T[]/=T
+//         "_arrayExpSliceDivass_f",       // T[]/=T
+// 
+//         "_arrayExpSliceMinSliceAssign_a",
+//         "_arrayExpSliceMinSliceAssign_d",   // T[]=T-T[]
+//         "_arrayExpSliceMinSliceAssign_f",   // T[]=T-T[]
+//         "_arrayExpSliceMinSliceAssign_g",
+//         "_arrayExpSliceMinSliceAssign_h",
+//         "_arrayExpSliceMinSliceAssign_i",
+//         "_arrayExpSliceMinSliceAssign_k",
+//         "_arrayExpSliceMinSliceAssign_s",
+//         "_arrayExpSliceMinSliceAssign_t",
+//         "_arrayExpSliceMinSliceAssign_u",
+//         "_arrayExpSliceMinSliceAssign_w",
+// 
+//         "_arrayExpSliceMinass_a",
+//         "_arrayExpSliceMinass_d",       // T[]-=T
+//         "_arrayExpSliceMinass_f",       // T[]-=T
+//         "_arrayExpSliceMinass_g",
+//         "_arrayExpSliceMinass_h",
+//         "_arrayExpSliceMinass_i",
+//         "_arrayExpSliceMinass_k",
+//         "_arrayExpSliceMinass_s",
+//         "_arrayExpSliceMinass_t",
+//         "_arrayExpSliceMinass_u",
+//         "_arrayExpSliceMinass_w",
+// 
+//         "_arrayExpSliceMulass_d",       // T[]*=T
+//         "_arrayExpSliceMulass_f",       // T[]*=T
+//         "_arrayExpSliceMulass_i",
+//         "_arrayExpSliceMulass_k",
+//         "_arrayExpSliceMulass_s",
+//         "_arrayExpSliceMulass_t",
+//         "_arrayExpSliceMulass_u",
+//         "_arrayExpSliceMulass_w",
+// 
+//         "_arraySliceExpAddSliceAssign_a",
+//         "_arraySliceExpAddSliceAssign_d",   // T[]=T[]+T
+//         "_arraySliceExpAddSliceAssign_f",   // T[]=T[]+T
+//         "_arraySliceExpAddSliceAssign_g",
+//         "_arraySliceExpAddSliceAssign_h",
+//         "_arraySliceExpAddSliceAssign_i",
+//         "_arraySliceExpAddSliceAssign_k",
+//         "_arraySliceExpAddSliceAssign_s",
+//         "_arraySliceExpAddSliceAssign_t",
+//         "_arraySliceExpAddSliceAssign_u",
+//         "_arraySliceExpAddSliceAssign_w",
+// 
+//         "_arraySliceExpDivSliceAssign_d",   // T[]=T[]/T
+//         "_arraySliceExpDivSliceAssign_f",   // T[]=T[]/T
+// 
+//         "_arraySliceExpMinSliceAssign_a",
+//         "_arraySliceExpMinSliceAssign_d",   // T[]=T[]-T
+//         "_arraySliceExpMinSliceAssign_f",   // T[]=T[]-T
+//         "_arraySliceExpMinSliceAssign_g",
+//         "_arraySliceExpMinSliceAssign_h",
+//         "_arraySliceExpMinSliceAssign_i",
+//         "_arraySliceExpMinSliceAssign_k",
+//         "_arraySliceExpMinSliceAssign_s",
+//         "_arraySliceExpMinSliceAssign_t",
+//         "_arraySliceExpMinSliceAssign_u",
+//         "_arraySliceExpMinSliceAssign_w",
+// 
+//         "_arraySliceExpMulSliceAddass_d",   // T[] += T[]*T
+//         "_arraySliceExpMulSliceAddass_f",
+//         "_arraySliceExpMulSliceAddass_r",
+// 
+//         "_arraySliceExpMulSliceAssign_d",   // T[]=T[]*T
+//         "_arraySliceExpMulSliceAssign_f",   // T[]=T[]*T
+//         "_arraySliceExpMulSliceAssign_i",
+//         "_arraySliceExpMulSliceAssign_k",
+//         "_arraySliceExpMulSliceAssign_s",
+//         "_arraySliceExpMulSliceAssign_t",
+//         "_arraySliceExpMulSliceAssign_u",
+//         "_arraySliceExpMulSliceAssign_w",
+// 
+//         "_arraySliceExpMulSliceMinass_d",   // T[] -= T[]*T
+//         "_arraySliceExpMulSliceMinass_f",
+//         "_arraySliceExpMulSliceMinass_r",
+// 
+//         "_arraySliceSliceAddSliceAssign_a",
+//         "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
+//         "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
+//         "_arraySliceSliceAddSliceAssign_g",
+//         "_arraySliceSliceAddSliceAssign_h",
+//         "_arraySliceSliceAddSliceAssign_i",
+//         "_arraySliceSliceAddSliceAssign_k",
+//         "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
+//         "_arraySliceSliceAddSliceAssign_s",
+//         "_arraySliceSliceAddSliceAssign_t",
+//         "_arraySliceSliceAddSliceAssign_u",
+//         "_arraySliceSliceAddSliceAssign_w",
+// 
+//         "_arraySliceSliceAddass_a",
+//         "_arraySliceSliceAddass_d",     // T[]+=T[]
+//         "_arraySliceSliceAddass_f",     // T[]+=T[]
+//         "_arraySliceSliceAddass_g",
+//         "_arraySliceSliceAddass_h",
+//         "_arraySliceSliceAddass_i",
+//         "_arraySliceSliceAddass_k",
+//         "_arraySliceSliceAddass_s",
+//         "_arraySliceSliceAddass_t",
+//         "_arraySliceSliceAddass_u",
+//         "_arraySliceSliceAddass_w",
+// 
+//         "_arraySliceSliceMinSliceAssign_a",
+//         "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
+//         "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
+//         "_arraySliceSliceMinSliceAssign_g",
+//         "_arraySliceSliceMinSliceAssign_h",
+//         "_arraySliceSliceMinSliceAssign_i",
+//         "_arraySliceSliceMinSliceAssign_k",
+//         "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
+//         "_arraySliceSliceMinSliceAssign_s",
+//         "_arraySliceSliceMinSliceAssign_t",
+//         "_arraySliceSliceMinSliceAssign_u",
+//         "_arraySliceSliceMinSliceAssign_w",
+// 
+//         "_arraySliceSliceMinass_a",
+//         "_arraySliceSliceMinass_d",     // T[]-=T[]
+//         "_arraySliceSliceMinass_f",     // T[]-=T[]
+//         "_arraySliceSliceMinass_g",
+//         "_arraySliceSliceMinass_h",
+//         "_arraySliceSliceMinass_i",
+//         "_arraySliceSliceMinass_k",
+//         "_arraySliceSliceMinass_s",
+//         "_arraySliceSliceMinass_t",
+//         "_arraySliceSliceMinass_u",
+//         "_arraySliceSliceMinass_w",
+// 
+//         "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
+//         "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
+//         "_arraySliceSliceMulSliceAssign_i",
+//         "_arraySliceSliceMulSliceAssign_k",
+//         "_arraySliceSliceMulSliceAssign_s",
+//         "_arraySliceSliceMulSliceAssign_t",
+//         "_arraySliceSliceMulSliceAssign_u",
+//         "_arraySliceSliceMulSliceAssign_w",
+// 
+//         "_arraySliceSliceMulass_d",     // T[]*=T[]
+//         "_arraySliceSliceMulass_f",     // T[]*=T[]
+//         "_arraySliceSliceMulass_i",
+//         "_arraySliceSliceMulass_k",
+//         "_arraySliceSliceMulass_s",
+//         "_arraySliceSliceMulass_t",
+//         "_arraySliceSliceMulass_u",
+//         "_arraySliceSliceMulass_w",
+//     };
+// 
+//     int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
+//     if (i == -1)
+//     {
+// #ifdef DEBUG    // Make sure our array is alphabetized
+//         for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
+//         {
+//         if (strcmp(name, libArrayopFuncs[i]) == 0)
+//             assert(0);
+//         }
+// #endif
+
+        /* Not in library, so generate it.
+         * Construct the function body:
+         *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
+         *      loopbody;
+         *  return p;
+         */
+
+        Arguments *fparams = new Arguments();
+        Expression *loopbody = buildArrayLoop(fparams);
+        Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/];
+#if DMDV1
+        // for (size_t i = 0; i < p.length; i++)
+        Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
+        Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
+        Statement *s1 = new ForStatement(0,
+        new DeclarationStatement(0, d),
+        new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
+        new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
+        new ExpStatement(0, loopbody));
+#else
+        // foreach (i; 0 .. p.length)
+        Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
+        new Argument(0, NULL, Id::p, NULL),
+        new IntegerExp(0, 0, Type::tint32),
+        new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
+        new ExpStatement(0, loopbody));
+#endif
+        Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
+        //printf("s2: %s\n", s2->toChars());
+        Statement *fbody = new CompoundStatement(0, s1, s2);
+
+        /* Construct the function
+         */
+        TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
+        //printf("ftype: %s\n", ftype->toChars());
+        fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype);
+        fd->fbody = fbody;
+        fd->protection = PROTprotected;
+        fd->linkage = LINKd;
+
+        // special attention for array ops
+        fd->isArrayOp = true;
+
+        sc->module->members->push(fd);
+
+        sc = sc->push();
+        sc->parent = sc->module;
+        sc->stc = 0;
+        sc->linkage = LINKd;
+        fd->semantic(sc);
+        sc->pop();
+//     }
+//     else
+//     {   /* In library, refer to it.
+//          */
+//         // FIXME
+//         fd = FuncDeclaration::genCfunc(NULL, type, name);
+//     }
+    sv->ptrvalue = fd;  // cache symbol in hash table
+    }
+
+    /* Call the function fd(arguments)
+     */
+    Expression *ec = new VarExp(0, fd);
+    Expression *e = new CallExp(loc, ec, arguments);
+    e->type = type;
+    return e;
+}
+
+/******************************************
+ * Construct the identifier for the array operation function,
+ * and build the argument list to pass to it.
+ */
+
+void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    buf->writestring("Exp");
+    arguments->shift(this);
+}
+
+void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    buf->writestring("Slice");
+    arguments->shift(this);
+}
+
+void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    /* Evaluate assign expressions right to left
+     */
+    e2->buildArrayIdent(buf, arguments);
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Assign");
+}
+
+#define X(Str) \
+void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
+{							\
+    /* Evaluate assign expressions right to left	\
+     */							\
+    e2->buildArrayIdent(buf, arguments);		\
+    e1->buildArrayIdent(buf, arguments);		\
+    buf->writestring(#Str);				\
+    buf->writestring("ass");				\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Neg");
+}
+
+void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
+{
+    e1->buildArrayIdent(buf, arguments);
+    buf->writestring("Com");
+}
+
+#define X(Str) \
+void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)	\
+{									\
+    /* Evaluate assign expressions left to right			\
+     */									\
+    e1->buildArrayIdent(buf, arguments);				\
+    e2->buildArrayIdent(buf, arguments);				\
+    buf->writestring(#Str);						\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+/******************************************
+ * Construct the inner loop for the array operation function,
+ * and build the parameter list.
+ */
+
+Expression *Expression::buildArrayLoop(Arguments *fparams)
+{
+    Identifier *id = Identifier::generateId("c", fparams->dim);
+    Argument *param = new Argument(0, type, id, NULL);
+    fparams->shift(param);
+    Expression *e = new IdentifierExp(0, id);
+    return e;
+}
+
+Expression *SliceExp::buildArrayLoop(Arguments *fparams)
+{
+    Identifier *id = Identifier::generateId("p", fparams->dim);
+    Argument *param = new Argument(STCconst, type, id, NULL);
+    fparams->shift(param);
+    Expression *e = new IdentifierExp(0, id);
+    Expressions *arguments = new Expressions();
+    Expression *index = new IdentifierExp(0, Id::p);
+    arguments->push(index);
+    e = new ArrayExp(0, e, arguments);
+    return e;
+}
+
+Expression *AssignExp::buildArrayLoop(Arguments *fparams)
+{
+    /* Evaluate assign expressions right to left
+     */
+    Expression *ex2 = e2->buildArrayLoop(fparams);
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Argument *param = (Argument *)fparams->data[0];
+    param->storageClass = 0;
+    Expression *e = new AssignExp(0, ex1, ex2);
+    return e;
+}
+
+#define X(Str) \
+Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams)	\
+{								\
+    /* Evaluate assign expressions right to left		\
+     */								\
+    Expression *ex2 = e2->buildArrayLoop(fparams);		\
+    Expression *ex1 = e1->buildArrayLoop(fparams);		\
+    Argument *param = (Argument *)fparams->data[0];		\
+    param->storageClass = 0;					\
+    Expression *e = new Str##AssignExp(0, ex1, ex2);		\
+    return e;							\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+Expression *NegExp::buildArrayLoop(Arguments *fparams)
+{
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Expression *e = new NegExp(0, ex1);
+    return e;
+}
+
+Expression *ComExp::buildArrayLoop(Arguments *fparams)
+{
+    Expression *ex1 = e1->buildArrayLoop(fparams);
+    Expression *e = new ComExp(0, ex1);
+    return e;
+}
+
+#define X(Str) \
+Expression *Str##Exp::buildArrayLoop(Arguments *fparams)	\
+{								\
+    /* Evaluate assign expressions left to right		\
+     */								\
+    Expression *ex1 = e1->buildArrayLoop(fparams);		\
+    Expression *ex2 = e2->buildArrayLoop(fparams);		\
+    Expression *e = new Str##Exp(0, ex1, ex2);			\
+    return e;							\
+}
+
+X(Add)
+X(Min)
+X(Mul)
+X(Div)
+X(Mod)
+X(Xor)
+X(And)
+X(Or)
+
+#undef X
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/arraytypes.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,51 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2006-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ARRAYTYPES_H
+#define DMD_ARRAYTYPES_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#include "root.h"
+
+struct Expression;
+struct Statement;
+struct BaseClass;
+struct TemplateParameter;
+struct FuncDeclaration;
+struct Identifier;
+struct Initializer;
+
+struct TemplateParameters : Array { };
+
+struct Expressions : Array { };
+
+struct Statements : Array { };
+
+struct BaseClasses : Array { };
+
+struct ClassDeclarations : Array { };
+
+struct Dsymbols : Array { };
+
+struct Objects : Array { };
+
+struct FuncDeclarations : Array { };
+
+struct Arguments : Array { };
+
+struct Identifiers : Array { };
+
+struct Initializers : Array { };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/artistic.txt	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,117 @@
+
+
+
+
+			 The "Artistic License"
+
+				Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+	"Package" refers to the collection of files distributed by the
+	Copyright Holder, and derivatives of that collection of files
+	created through textual modification.
+
+	"Standard Version" refers to such a Package if it has not been
+	modified, or has been modified in accordance with the wishes
+	of the Copyright Holder as specified below.
+
+	"Copyright Holder" is whoever is named in the copyright or
+	copyrights for the package.
+
+	"You" is you, if you're thinking about copying or distributing
+	this Package.
+
+	"Reasonable copying fee" is whatever you can justify on the
+	basis of media cost, duplication charges, time of people involved,
+	and so on.  (You will not be required to justify it to the
+	Copyright Holder, but only to the computing community at large
+	as a market that must bear the fee.)
+
+	"Freely Available" means that no fee is charged for the item
+	itself, though there may be fees involved in handling the item.
+	It also means that recipients of the item may redistribute it
+	under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.  You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The source code and object code supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.
+
+7. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution.  Such use shall not be
+construed as a distribution of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+				The End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/attrib.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,1473 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#elif POSIX
+#include "../root/mem.h"
+#endif
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "cond.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "module.h"
+#include "parse.h"
+#include "template.h"
+
+#include "../gen/enums.h"
+#include "../gen/logger.h"
+
+extern void obj_includelib(const char *name);
+void obj_startaddress(Symbol *s);
+
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Array *decl)
+	: Dsymbol()
+{
+    this->decl = decl;
+}
+
+Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    return decl;
+}
+
+int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    int m = 0;
+    Array *d = include(sc, sd);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    m |= s->addMember(sc, sd, m | memnum);
+	}
+    }
+    return m;
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->semantic2(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->semantic3(sc);
+	}
+    }
+}
+
+void AttribDeclaration::inlineScan()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
+	    s->inlineScan();
+	}
+    }
+}
+
+void AttribDeclaration::addComment(unsigned char *comment)
+{
+    if (comment)
+    {
+	Array *d = include(NULL, NULL);
+
+	if (d)
+	{
+	    for (unsigned i = 0; i < d->dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)d->data[i];
+		//printf("AttribDeclaration::addComment %s\n", s->toChars());
+		s->addComment(comment);
+	    }
+	}
+    }
+}
+
+void AttribDeclaration::emitComment(Scope *sc)
+{
+    //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+    /* If generating doc comment, skip this because if we're inside
+     * a template, then include(NULL, NULL) will fail.
+     */
+//    if (sc->docbuf)
+//	return;
+
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+	    s->emitComment(sc);
+	}
+    }
+}
+
+void AttribDeclaration::toObjFile(int multiobj)
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->toObjFile(multiobj);
+	}
+    }
+}
+
+int AttribDeclaration::cvMember(unsigned char *p)
+{
+    int nwritten = 0;
+    int n;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    n = s->cvMember(p);
+	    if (p)
+		p += n;
+	    nwritten += n;
+	}
+    }
+    return nwritten;
+}
+
+int AttribDeclaration::hasPointers()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (size_t i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+	    if (s->hasPointers())
+		return 1;
+	}
+    }
+    return 0;
+}
+
+const char *AttribDeclaration::kind()
+{
+    return "attribute";
+}
+
+int AttribDeclaration::oneMember(Dsymbol **ps)
+{
+    Array *d = include(NULL, NULL);
+
+    return Dsymbol::oneMembers(d, ps);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->checkCtorConstInit();
+	}
+    }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{   Dsymbol *s = (Dsymbol *)d->data[i];
+	    s->addLocalClass(aclasses);
+	}
+    }
+}
+
+
+void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (decl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writeByte('}');
+    }
+    else
+	buf->writeByte(';');
+    buf->writenl();
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StorageClassDeclaration *scd;
+
+    assert(!s);
+    scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+    return scd;
+}
+
+void StorageClassDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	unsigned stc_save = sc->stc;
+
+	/* These sets of storage classes are mutually exclusive,
+	 * so choose the innermost or most recent one.
+	 */
+	if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest))
+	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest);
+	if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest))
+	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest);
+	if (stc & (STCconst | STCinvariant | STCmanifest))
+	    sc->stc &= ~(STCconst | STCinvariant | STCmanifest);
+	sc->stc |= stc;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->stc = stc_save;
+    }
+    else
+	sc->stc = stc;
+}
+
+void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    struct SCstring
+    {
+	int stc;
+	enum TOK tok;
+    };
+
+    static SCstring table[] =
+    {
+	{ STCauto,         TOKauto },
+	{ STCscope,        TOKscope },
+	{ STCstatic,       TOKstatic },
+	{ STCextern,       TOKextern },
+	{ STCconst,        TOKconst },
+	{ STCinvariant,    TOKimmutable },
+	{ STCshared,       TOKshared },
+	{ STCfinal,        TOKfinal },
+	{ STCabstract,     TOKabstract },
+	{ STCsynchronized, TOKsynchronized },
+	{ STCdeprecated,   TOKdeprecated },
+	{ STCoverride,     TOKoverride },
+	{ STCnothrow,      TOKnothrow },
+	{ STCpure,         TOKpure },
+	{ STCref,          TOKref },
+	{ STCtls,          TOKtls },
+    };
+
+    int written = 0;
+    for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
+    {
+	if (stc & table[i].stc)
+	{
+	    if (written)
+		buf->writeByte(' ');
+	    written = 1;
+	    buf->writestring(Token::toChars(table[i].tok));
+	}
+    }
+
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+    linkage = p;
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+    LinkDeclaration *ld;
+
+    assert(!s);
+    ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+    return ld;
+}
+
+void LinkDeclaration::semantic(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::semantic3(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic3(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   const char *p;
+
+    switch (linkage)
+    {
+	case LINKd:		p = "D";		break;
+	case LINKc:		p = "C";		break;
+	case LINKcpp:		p = "C++";		break;
+	case LINKwindows:	p = "Windows";		break;
+	case LINKpascal:	p = "Pascal";		break;
+
+    // LDC
+    case LINKintrinsic: p = "Intrinsic"; break;
+
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring("extern (");
+    buf->writestring(p);
+    buf->writestring(") ");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+char *LinkDeclaration::toChars()
+{
+    return (char *)"extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    protection = p;
+    //printf("decl = %p\n", decl);
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ProtDeclaration *pd;
+
+    assert(!s);
+    pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void ProtDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	enum PROT protection_save = sc->protection;
+	int explicitProtection_save = sc->explicitProtection;
+
+	sc->protection = protection;
+	sc->explicitProtection = 1;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->protection = protection_save;
+	sc->explicitProtection = explicitProtection_save;
+    }
+    else
+    {	sc->protection = protection;
+	sc->explicitProtection = 1;
+    }
+}
+
+void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   const char *p;
+
+    switch (protection)
+    {
+	case PROTprivate:	p = "private";		break;
+	case PROTpackage:	p = "package";		break;
+	case PROTprotected:	p = "protected";	break;
+	case PROTpublic:	p = "public";		break;
+	case PROTexport:	p = "export";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring(p);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    salign = sa;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AlignDeclaration *ad;
+
+    assert(!s);
+    ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AlignDeclaration::semantic(Scope *sc)
+{
+// LDC
+// we only support packed structs, as from the spec: align(1) struct Packed { ... }
+// other alignments are simply ignored. my tests show this is what llvm-gcc does too ...
+
+    //printf("\tAlignDeclaration::semantic '%s'\n",toChars());
+    if (decl)
+    {	unsigned salign_save = sc->structalign;
+
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+        if (s->isStructDeclaration() && salign == 1)
+        {
+            sc->structalign = salign;
+            s->semantic(sc);
+            sc->structalign = salign_save;
+        }
+        else
+        {
+            s->semantic(sc);
+        }
+	}
+	sc->structalign = salign_save;
+    }
+    else
+    assert(0 && "what kind of align use triggers this?");
+}
+
+
+void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("align (%d)", salign);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->isunion = isunion;
+    this->scope = NULL;
+    this->sem = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AnonDeclaration *ad;
+
+    assert(!s);
+    ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+    Scope *scx = NULL;
+    if (scope)
+    {   sc = scope;
+	scx = scope;
+	scope = NULL;
+    }
+
+    assert(sc->parent);
+
+    Dsymbol *parent = sc->parent->pastMixin();
+    AggregateDeclaration *ad = parent->isAggregateDeclaration();
+
+    if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration()))
+    {
+	error("can only be a part of an aggregate");
+	return;
+    }
+
+    if (decl)
+    {
+	AnonymousAggregateDeclaration aad;
+	int adisunion;
+
+	if (sc->anonAgg)
+	{   ad = sc->anonAgg;
+	    adisunion = sc->inunion;
+	}
+	else
+	    adisunion = ad->isUnionDeclaration() != NULL;
+
+//	printf("\tsc->anonAgg = %p\n", sc->anonAgg);
+//	printf("\tad  = %p\n", ad);
+//	printf("\taad = %p\n", &aad);
+
+	sc = sc->push();
+	sc->anonAgg = &aad;
+	sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls);
+	sc->inunion = isunion;
+	sc->offset = 0;
+	sc->flags = 0;
+	aad.structalign = sc->structalign;
+	aad.parent = ad;
+
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	    if (isunion)
+		sc->offset = 0;
+	    if (aad.sizeok == 2)
+	    {
+		break;
+	    }
+	}
+	sc = sc->pop();
+
+	// If failed due to forward references, unwind and try again later
+	if (aad.sizeok == 2)
+	{
+	    ad->sizeok = 2;
+	    //printf("\tsetting ad->sizeok %p to 2\n", ad);
+	    if (!sc->anonAgg)
+	    {
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    //printf("\tforward reference %p\n", this);
+	    return;
+	}
+	if (sem == 0)
+	{   Module::dprogress++;
+	    sem = 1;
+	    //printf("\tcompleted %p\n", this);
+	}
+	else
+	    ;//printf("\talready completed %p\n", this);
+
+	// 0 sized structs are set to 1 byte
+	if (aad.structsize == 0)
+	{
+	    aad.structsize = 1;
+	    aad.alignsize = 1;
+	}
+
+	// Align size of anonymous aggregate
+//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset);
+	ad->alignmember(aad.structalign, aad.alignsize, &sc->offset);
+	//ad->structsize = sc->offset;
+//printf("sc->offset = %d\n", sc->offset);
+
+	// Add members of aad to ad
+	//printf("\tadding members of aad (%p) to '%s'\n", &aad, ad->toChars());
+	for (unsigned i = 0; i < aad.fields.dim; i++)
+	{
+	    VarDeclaration *v = (VarDeclaration *)aad.fields.data[i];
+
+	    v->offset += sc->offset;
+
+        // LDC
+        if (!v->anonDecl)
+            v->anonDecl = this;
+
+	    ad->fields.push(v);
+	}
+
+	// Add size of aad to ad
+	if (adisunion)
+	{
+	    if (aad.structsize > ad->structsize)
+		ad->structsize = aad.structsize;
+	    sc->offset = 0;
+	}
+	else
+	{
+	    ad->structsize = sc->offset + aad.structsize;
+	    sc->offset = ad->structsize;
+	}
+
+	if (ad->alignsize < aad.alignsize)
+	    ad->alignsize = aad.alignsize;
+    }
+}
+
+
+void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf(isunion ? "union" : "struct");
+    buf->writestring("\n{\n");
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    //buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring("}\n");
+}
+
+const char *AnonDeclaration::kind()
+{
+    return (isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+static bool parseStringExp(Expression* e, std::string& res)
+{
+    StringExp *s = NULL;
+
+    e = e->optimize(WANTvalue);
+    if (e->op == TOKstring && (s = (StringExp *)e))
+    {
+        char* str = (char*)s->string;
+        res = str;
+        return true;
+    }
+    return false;
+}
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+    PragmaDeclaration *pd;
+
+    assert(!s);
+    pd = new PragmaDeclaration(loc, ident,
+	Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{   // Should be merged with PragmaStatement
+
+#if IN_LLVM
+    int llvm_internal = 0;
+    std::string arg1str;
+
+#endif
+
+    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+    if (ident == Id::msg)
+    {
+	if (args)
+	{
+	    for (size_t i = 0; i < args->dim; i++)
+	    {
+		Expression *e = (Expression *)args->data[i];
+
+		e = e->semantic(sc);
+		e = e->optimize(WANTvalue | WANTinterpret);
+		if (e->op == TOKstring)
+		{
+		    StringExp *se = (StringExp *)e;
+		    fprintf(stdmsg, "%.*s", (int)se->len, se->string);
+		}
+		else
+		    error("string expected for message, not '%s'", e->toChars());
+	    }
+	    fprintf(stdmsg, "\n");
+	}
+	goto Lnodecl;
+    }
+    else if (ident == Id::lib)
+    {
+	if (!args || args->dim != 1)
+	    error("string expected for library name");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    if (e->op != TOKstring)
+		error("string expected for library name, not '%s'", e->toChars());
+	    else if (global.params.verbose)
+	    {
+		StringExp *se = (StringExp *)e;
+		char *name = (char *)mem.malloc(se->len + 1);
+		memcpy(name, se->string, se->len);
+		name[se->len] = 0;
+		printf("library   %s\n", name);
+		mem.free(name);
+	    }
+	}
+	goto Lnodecl;
+    }
+#if IN_GCC
+    else if (ident == Id::GNU_asm)
+    {
+	if (! args || args->dim != 2)
+	    error("identifier and string expected for asm name");
+	else
+	{
+	    Expression *e;
+	    Declaration *d = NULL;
+	    StringExp *s = NULL;
+
+	    e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    if (e->op == TOKvar)
+	    {
+		d = ((VarExp *)e)->var;
+		if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
+		    d = NULL;
+	    }
+	    if (!d)
+		error("first argument of GNU_asm must be a function or variable declaration");
+
+	    e = (Expression *)args->data[1];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue);
+	    if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
+		s = ((StringExp *)e);
+	    else
+		error("second argument of GNU_asm must be a char string");
+
+	    if (d && s)
+		d->c_ident = Lexer::idPool((char*) s->string);
+	}
+	goto Lnodecl;
+    }
+#endif
+    else if (ident == Id::startaddress)
+    {
+	if (!args || args->dim != 1)
+	    error("function name expected for start address");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    Dsymbol *sa = getDsymbol(e);
+	    if (!sa || !sa->isFuncDeclaration())
+		error("function name expected for start address, not '%s'", e->toChars());
+	}
+	goto Lnodecl;
+    }
+
+    /////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////
+    // LDC
+#if IN_LLVM
+
+    // pragma(intrinsic, "string") { funcdecl(s) }
+    else if (ident == Id::intrinsic)
+    {
+        Expression* expr = (Expression *)args->data[0];
+        expr = expr->semantic(sc);
+        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
+        {
+             error("requires exactly 1 string literal parameter");
+             fatal();
+        }
+        llvm_internal = LLVMintrinsic;
+    }
+
+    // pragma(notypeinfo) { typedecl(s) }
+    else if (ident == Id::no_typeinfo)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMno_typeinfo;
+    }
+
+    // pragma(nomoduleinfo) ;
+    else if (ident == Id::no_moduleinfo)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMno_moduleinfo;
+    }
+
+    // pragma(alloca) { funcdecl(s) }
+    else if (ident == Id::Alloca)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMalloca;
+    }
+
+    // pragma(va_start) { templdecl(s) }
+    else if (ident == Id::vastart)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_start;
+    }
+
+    // pragma(va_copy) { funcdecl(s) }
+    else if (ident == Id::vacopy)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_copy;
+    }
+
+    // pragma(va_end) { funcdecl(s) }
+    else if (ident == Id::vaend)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_end;
+    }
+
+    // pragma(va_arg) { templdecl(s) }
+    else if (ident == Id::vaarg)
+    {
+        if (args && args->dim > 0)
+        {
+             error("takes no parameters");
+             fatal();
+        }
+        llvm_internal = LLVMva_arg;
+    }
+    
+    // pragma(ldc, "string") { templdecl(s) }
+    else if (ident == Id::ldc)
+    {
+        Expression* expr = (Expression *)args->data[0];
+        expr = expr->semantic(sc);
+        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
+        {
+             error("requires exactly 1 string literal parameter");
+             fatal();
+        }
+        else if (arg1str == "verbose")
+        {
+            sc->module->llvmForceLogging = true;
+        }
+        else
+        {
+            error("command '%s' invalid");
+            fatal();
+        }
+    }
+
+#endif
+    // LDC
+    /////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////
+
+    else if (global.params.ignoreUnsupportedPragmas)
+    {
+	if (global.params.verbose)
+	{
+	    /* Print unrecognized pragmas
+	     */
+	    printf("pragma    %s", ident->toChars());
+	    if (args)
+	    {
+		for (size_t i = 0; i < args->dim; i++)
+		{
+		    Expression *e = (Expression *)args->data[i];
+		    e = e->semantic(sc);
+		    e = e->optimize(WANTvalue | WANTinterpret);
+		    if (i == 0)
+			printf(" (");
+		    else
+			printf(",");
+		    printf("%s", e->toChars());
+		}
+		if (args->dim)
+		    printf(")");
+	    }
+	    printf("\n");
+	}
+	goto Lnodecl;
+    }
+    else
+	error("unrecognized pragma(%s)", ident->toChars());
+
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+
+// LDC
+#if IN_LLVM
+
+        if (llvm_internal)
+        {
+        if (s->llvmInternal)
+        {
+            error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars());
+            fatal();
+        }
+        switch(llvm_internal)
+        {
+        case LLVMintrinsic:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+                fd->intrinsicName = arg1str;
+                fd->linkage = LINKintrinsic;
+                ((TypeFunction*)fd->type)->linkage = LINKintrinsic;
+            }
+            else if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                td->llvmInternal = llvm_internal;
+                td->intrinsicName = arg1str;
+            }
+            else
+            {
+                error("only allowed on function declarations");
+                fatal();
+            }
+            break;
+
+        case LLVMva_start:
+        case LLVMva_arg:
+            if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                if (td->parameters->dim != 1)
+                {
+                    error("the '%s' pragma template must have exactly one template parameter", ident->toChars());
+                    fatal();
+                }
+                else if (!td->onemember)
+                {
+                    error("the '%s' pragma template must have exactly one member", ident->toChars());
+                    fatal();
+                }
+                else if (td->overnext || td->overroot)
+                {
+                    error("the '%s' pragma template must not be overloaded", ident->toChars());
+                    fatal();
+                }
+                td->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
+                fatal();
+            }
+            break;
+
+        case LLVMva_copy:
+        case LLVMva_end:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma is only allowed on function declarations", ident->toChars());
+                fatal();
+            }
+            break;
+
+        case LLVMno_typeinfo:
+            s->llvmInternal = llvm_internal;
+            break;
+
+        case LLVMalloca:
+            if (FuncDeclaration* fd = s->isFuncDeclaration())
+            {
+                fd->llvmInternal = llvm_internal;
+            }
+            else
+            {
+                error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars());
+                fatal();
+            }
+            break;
+
+        default:
+            warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
+        }
+        }
+
+#endif // LDC
+
+    }
+    }
+    return;
+
+Lnodecl:
+    if (decl)
+	error("pragma is missing closing ';'");
+}
+
+int PragmaDeclaration::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+const char *PragmaDeclaration::kind()
+{
+    return "pragma";
+}
+
+void PragmaDeclaration::toObjFile(int multiobj)
+{
+    if (ident == Id::lib)
+    {
+	assert(args && args->dim == 1);
+
+	Expression *e = (Expression *)args->data[0];
+
+	assert(e->op == TOKstring);
+
+	StringExp *se = (StringExp *)e;
+	char *name = (char *)mem.malloc(se->len + 1);
+	memcpy(name, se->string, se->len);
+	name[se->len] = 0;
+	obj_includelib(name);
+    }
+    else if (ident == Id::startaddress)
+    {
+	assert(args && args->dim == 1);
+	Expression *e = (Expression *)args->data[0];
+	Dsymbol *sa = getDsymbol(e);
+	FuncDeclaration *f = sa->isFuncDeclaration();
+	assert(f);
+	Symbol *s = f->toSymbol();
+    assert(0 && "startaddress pragma not implemented");
+// 	obj_startaddress(s);
+    }
+    AttribDeclaration::toObjFile(multiobj);
+}
+
+void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("pragma (%s", ident->toChars());
+    if (args && args->dim)
+    {
+        buf->writestring(", ");
+        argsToCBuffer(buf, args, hgs);
+    }
+    buf->writeByte(')');
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl)
+	: AttribDeclaration(decl)
+{
+    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+    this->condition = condition;
+    this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ConditionalDeclaration *dd;
+
+    assert(!s);
+    dd = new ConditionalDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int ConditionalDeclaration::oneMember(Dsymbol **ps)
+{
+    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+    if (condition->inc)
+    {
+	Array *d = condition->include(NULL, NULL) ? decl : elsedecl;
+	return Dsymbol::oneMembers(d, ps);
+    }
+    *ps = NULL;
+    return TRUE;
+}
+
+void ConditionalDeclaration::emitComment(Scope *sc)
+{
+    //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+    if (condition->inc)
+    {
+	AttribDeclaration::emitComment(sc);
+    }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("ConditionalDeclaration::include()\n");
+    assert(condition);
+    return condition->include(sc, sd) ? decl : elsedecl;
+}
+
+
+void ConditionalDeclaration::addComment(unsigned char *comment)
+{
+    /* Because addComment is called by the parser, if we called
+     * include() it would define a version before it was used.
+     * But it's no problem to drill down to both decl and elsedecl,
+     * so that's the workaround.
+     */
+
+    if (comment)
+    {
+	Array *d = decl;
+
+	for (int j = 0; j < 2; j++)
+	{
+	    if (d)
+	    {
+		for (unsigned i = 0; i < d->dim; i++)
+		{   Dsymbol *s;
+
+		    s = (Dsymbol *)d->data[i];
+		    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+		    s->addComment(comment);
+		}
+	    }
+	    d = elsedecl;
+	}
+    }
+}
+
+void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    condition->toCBuffer(buf, hgs);
+    if (decl || elsedecl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	if (decl)
+	{
+	    for (unsigned i = 0; i < decl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)decl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	}
+	buf->writeByte('}');
+	if (elsedecl)
+	{
+	    buf->writenl();
+	    buf->writestring("else");
+	    buf->writenl();
+	    buf->writeByte('{');
+	    buf->writenl();
+	    for (unsigned i = 0; i < elsedecl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)elsedecl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	    buf->writeByte('}');
+	}
+    }
+    else
+	buf->writeByte(':');
+    buf->writenl();
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+	Array *decl, Array *elsedecl)
+	: ConditionalDeclaration(condition, decl, elsedecl)
+{
+    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+    sd = NULL;
+    addisdone = 0;
+}
+
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticIfDeclaration *dd;
+
+    assert(!s);
+    dd = new StaticIfDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("StaticIfDeclaration::addMember() '%s'\n",toChars());
+    /* This is deferred until semantic(), so that
+     * expressions in the condition can refer to declarations
+     * in the same scope, such as:
+     *
+     * template Foo(int i)
+     * {
+     *     const int j = i + 1;
+     *     static if (j == 3)
+     *         const int k;
+     * }
+     */
+    this->sd = sd;
+    int m = 0;
+
+    if (memnum == 0)
+    {	m = AttribDeclaration::addMember(sc, sd, memnum);
+	addisdone = 1;
+    }
+    return m;
+}
+
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, sd);
+
+    //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+	if (!addisdone)
+	{   AttribDeclaration::addMember(sc, sd, 1);
+	    addisdone = 1;
+	}
+
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+const char *StaticIfDeclaration::kind()
+{
+    return "static if";
+}
+
+
+/***************************** CompileDeclaration *****************************/
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+    : AttribDeclaration(NULL)
+{
+    //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+    this->loc = loc;
+    this->exp = exp;
+    this->sd = NULL;
+    this->compiled = 0;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+    CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy());
+    return sc;
+}
+
+int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum);
+    this->sd = sd;
+    if (memnum == 0)
+    {	/* No members yet, so parse the mixin now
+	 */
+	compileIt(sc);
+	memnum |= AttribDeclaration::addMember(sc, sd, memnum);
+	compiled = 1;
+    }
+    return memnum;
+}
+
+void CompileDeclaration::compileIt(Scope *sc)
+{
+    //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum);
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    if (exp->op != TOKstring)
+    {	exp->error("argument to mixin must be a string, not (%s)", exp->toChars());
+    }
+    else
+    {
+	StringExp *se = (StringExp *)exp;
+	se = se->toUTF8(sc);
+	Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+	p.loc = loc;
+	p.nextToken();
+	decl = p.parseDeclDefs(0);
+	if (p.token.value != TOKeof)
+	    exp->error("incomplete mixin declaration (%s)", se->toChars());
+    }
+}
+
+void CompileDeclaration::semantic(Scope *sc)
+{
+    //printf("CompileDeclaration::semantic()\n");
+
+    if (!compiled)
+    {
+	compileIt(sc);
+	AttribDeclaration::addMember(sc, sd, 0);
+	compiled = 1;
+    }
+    AttribDeclaration::semantic(sc);
+}
+
+void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(");");
+    buf->writenl();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/attrib.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,168 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ATTRIB_H
+#define DMD_ATTRIB_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+struct Expression;
+struct Statement;
+struct LabelDsymbol;
+struct Initializer;
+struct Module;
+struct Condition;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+/**************************************************************/
+
+struct AttribDeclaration : Dsymbol
+{
+    Array *decl;	// array of Dsymbol's
+
+    AttribDeclaration(Array *decl);
+    virtual Array *include(Scope *sc, ScopeDsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    void addComment(unsigned char *comment);
+    void emitComment(Scope *sc);
+    const char *kind();
+    int oneMember(Dsymbol **ps);
+    int hasPointers();
+    void checkCtorConstInit();
+    void addLocalClass(ClassDeclarations *);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    AttribDeclaration *isAttribDeclaration() { return this; }
+
+    void toObjFile(int multiobj);			// compile to .obj file
+    int cvMember(unsigned char *p);
+};
+
+struct StorageClassDeclaration: AttribDeclaration
+{
+    unsigned stc;
+
+    StorageClassDeclaration(unsigned stc, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct LinkDeclaration : AttribDeclaration
+{
+    enum LINK linkage;
+
+    LinkDeclaration(enum LINK p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic3(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *toChars();
+};
+
+struct ProtDeclaration : AttribDeclaration
+{
+    enum PROT protection;
+
+    ProtDeclaration(enum PROT p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AlignDeclaration : AttribDeclaration
+{
+    unsigned salign;
+
+    AlignDeclaration(Loc loc, unsigned sa, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AnonDeclaration : AttribDeclaration
+{
+    int isunion;
+    Scope *scope;		// !=NULL means context to use
+    int sem;			// 1 if successful semantic()
+
+    AnonDeclaration(Loc loc, int isunion, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    const char *kind();
+};
+
+struct PragmaDeclaration : AttribDeclaration
+{
+    Expressions *args;		// array of Expression's
+
+    PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int oneMember(Dsymbol **ps);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    const char *kind();
+    void toObjFile(int multiobj);			// compile to .obj file
+};
+
+struct ConditionalDeclaration : AttribDeclaration
+{
+    Condition *condition;
+    Array *elsedecl;	// array of Dsymbol's for else block
+
+    ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int oneMember(Dsymbol **ps);
+    void emitComment(Scope *sc);
+    Array *include(Scope *sc, ScopeDsymbol *s);
+    void addComment(unsigned char *comment);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfDeclaration : ConditionalDeclaration
+{
+    ScopeDsymbol *sd;
+    int addisdone;
+
+    StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    const char *kind();
+};
+
+// Mixin declarations
+
+struct CompileDeclaration : AttribDeclaration
+{
+    Expression *exp;
+
+    ScopeDsymbol *sd;
+    int compiled;
+
+    CompileDeclaration(Loc loc, Expression *exp);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
+    void compileIt(Scope *sc);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+#endif /* DMD_ATTRIB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/builtin.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,102 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "mars.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "expression.h"
+#include "scope.h"
+#include "mtype.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "id.h"
+#include "module.h"
+
+/**********************************
+ * Determine if function is a builtin one.
+ */
+enum BUILTIN FuncDeclaration::isBuiltin()
+{
+    static const char FeZe[] = "FeZe";	// real function(real)
+
+    //printf("FuncDeclaration::isBuiltin() %s\n", toChars());
+    if (builtin == BUILTINunknown)
+    {
+	builtin = BUILTINnot;
+	if (parent && parent->isModule())
+	{
+	    if (parent->ident == Id::math &&
+		parent->parent && parent->parent->ident == Id::std &&
+		!parent->parent->parent)
+	    {
+		if (strcmp(type->deco, FeZe) == 0)
+		{
+		    if (ident == Id::sin)
+			builtin = BUILTINsin;
+		    else if (ident == Id::cos)
+			builtin = BUILTINcos;
+		    else if (ident == Id::tan)
+			builtin = BUILTINtan;
+		    else if (ident == Id::_sqrt)
+			builtin = BUILTINsqrt;
+		    else if (ident == Id::fabs)
+			builtin = BUILTINfabs;
+		    //printf("builtin = %d\n", builtin);
+		}
+	    }
+	}
+    }
+    return builtin;
+}
+
+
+/**************************************
+ * Evaluate builtin function.
+ * Return result; NULL if cannot evaluate it.
+ */
+
+Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments)
+{
+    assert(arguments && arguments->dim);
+    Expression *arg0 = (Expression *)arguments->data[0];
+    Expression *e = NULL;
+    switch (builtin)
+    {
+	case BUILTINsin:
+	    if (arg0->op == TOKfloat64)
+		e = new RealExp(0, sinl(arg0->toReal()), Type::tfloat80);
+	    break;
+
+	case BUILTINcos:
+	    if (arg0->op == TOKfloat64)
+		e = new RealExp(0, cosl(arg0->toReal()), Type::tfloat80);
+	    break;
+
+	case BUILTINtan:
+	    if (arg0->op == TOKfloat64)
+		e = new RealExp(0, tanl(arg0->toReal()), Type::tfloat80);
+	    break;
+
+	case BUILTINsqrt:
+	    if (arg0->op == TOKfloat64)
+		e = new RealExp(0, sqrtl(arg0->toReal()), Type::tfloat80);
+	    break;
+
+	case BUILTINfabs:
+	    if (arg0->op == TOKfloat64)
+		e = new RealExp(0, fabsl(arg0->toReal()), Type::tfloat80);
+	    break;
+    }
+    return e;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/cast.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,1688 @@
+
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#include "../root/mem.h"
+#endif
+
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+Expression *Expression::implicitCastTo(Scope *sc, Type *t)
+{
+    //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
+
+    MATCH match = implicitConvTo(t);
+    if (match)
+    {
+	if (global.params.warnings &&
+	    Type::impcnvWarn[type->toBasetype()->ty][t->toBasetype()->ty] &&
+	    op != TOKint64)
+	{
+	    Expression *e = optimize(WANTflags | WANTvalue);
+
+	    if (e->op == TOKint64)
+		return e->implicitCastTo(sc, t);
+
+	    warning("%s: implicit conversion of expression (%s) of type %s to %s can cause loss of data",
+		loc.toChars(), toChars(), type->toChars(), t->toChars());
+	}
+#if DMDV2
+	if (match == MATCHconst && t == type->constOf())
+	{
+	    Expression *e = copy();
+	    e->type = t;
+	    return e;
+	}
+#endif
+	return castTo(sc, t);
+    }
+
+    Expression *e = optimize(WANTflags | WANTvalue);
+    if (e != this)
+	return e->implicitCastTo(sc, t);
+
+#if 0
+printf("ty = %d\n", type->ty);
+print();
+type->print();
+printf("to:\n");
+t->print();
+printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
+//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
+fflush(stdout);
+#endif
+    if (!t->deco)
+    {	/* Can happen with:
+	 *    enum E { One }
+	 *    class A
+	 *    { static void fork(EDG dg) { dg(E.One); }
+	 *	alias void delegate(E) EDG;
+	 *    }
+	 * Should eventually make it work.
+	 */
+	error("forward reference to type %s", t->toChars());
+    }
+    else if (t->reliesOnTident())
+	error("forward reference to type %s", t->reliesOnTident()->toChars());
+
+    error("cannot implicitly convert expression (%s) of type %s to %s",
+	toChars(), type->toChars(), t->toChars());
+    return castTo(sc, t);
+}
+
+/*******************************************
+ * Return !=0 if we can implicitly convert this to type t.
+ * Don't do the actual cast.
+ */
+
+MATCH Expression::implicitConvTo(Type *t)
+{
+#if 0
+    printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    //static int nest; if (++nest == 10) halt();
+    if (!type)
+    {	error("%s is not an expression", toChars());
+	type = Type::terror;
+    }
+    Expression *e = optimize(WANTvalue | WANTflags);
+    if (e->type == t)
+	return MATCHexact;
+    if (e != this)
+    {	//printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
+	return e->implicitConvTo(t);
+    }
+    MATCH match = type->implicitConvTo(t);
+    if (match != MATCHnomatch)
+	return match;
+#if 0
+    Type *tb = t->toBasetype();
+    if (tb->ty == Tdelegate)
+    {	TypeDelegate *td = (TypeDelegate *)tb;
+	TypeFunction *tf = (TypeFunction *)td->nextOf();
+
+	if (!tf->varargs &&
+	    !(tf->arguments && tf->arguments->dim)
+	   )
+	{
+	    match = type->implicitConvTo(tf->nextOf());
+	    if (match)
+		return match;
+	    if (tf->nextOf()->toBasetype()->ty == Tvoid)
+		return MATCHconvert;
+	}
+    }
+#endif
+    return MATCHnomatch;
+}
+
+
+MATCH IntegerExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH m = type->implicitConvTo(t);
+    if (m >= MATCHconst)
+	return m;
+
+    TY ty = type->toBasetype()->ty;
+    TY toty = t->toBasetype()->ty;
+
+    if (m == MATCHnomatch && t->ty == Tenum)
+	goto Lno;
+
+    switch (ty)
+    {
+	case Tbit:
+	case Tbool:
+	    value &= 1;
+	    ty = Tint32;
+	    break;
+
+	case Tint8:
+	    value = (signed char)value;
+	    ty = Tint32;
+	    break;
+
+	case Tchar:
+	case Tuns8:
+	    value &= 0xFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint16:
+	    value = (short)value;
+	    ty = Tint32;
+	    break;
+
+	case Tuns16:
+	case Twchar:
+	    value &= 0xFFFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint32:
+	    value = (int)value;
+	    break;
+
+	case Tuns32:
+	case Tdchar:
+	    value &= 0xFFFFFFFF;
+	    ty = Tuns32;
+	    break;
+
+	default:
+	    break;
+    }
+
+    // Only allow conversion if no change in value
+    switch (toty)
+    {
+	case Tbit:
+	case Tbool:
+	    if ((value & 1) != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint8:
+	    if ((signed char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tchar:
+	case Tuns8:
+	    //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value);
+	    if ((unsigned char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint16:
+	    if ((short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns16:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint32:
+	    if (ty == Tuns32)
+	    {
+	    }
+	    else if ((int)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns32:
+	    if (ty == Tint32)
+	    {
+	    }
+	    else if ((unsigned)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tdchar:
+	    if (value > 0x10FFFFUL)
+		goto Lno;
+	    goto Lyes;
+
+	case Twchar:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tfloat32:
+	{
+	    volatile float f;
+	    if (type->isunsigned())
+	    {
+		f = (float)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (float)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat64:
+	{
+	    volatile double f;
+	    if (type->isunsigned())
+	    {
+		f = (double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat80:
+	{
+	    volatile long double f;
+	    if (type->isunsigned())
+	    {
+		f = (long double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (long double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tpointer:
+//printf("type = %s\n", type->toBasetype()->toChars());
+//printf("t = %s\n", t->toBasetype()->toChars());
+	    if (ty == Tpointer &&
+	        type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
+	    {	/* Allow things like:
+		 *	const char* P = cast(char *)3;
+		 *	char* q = P;
+		 */
+		goto Lyes;
+	    }
+	    break;
+    }
+    return Expression::implicitConvTo(t);
+
+Lyes:
+    //printf("MATCHconvert\n");
+    return MATCHconvert;
+
+Lno:
+    //printf("MATCHnomatch\n");
+    return MATCHnomatch;
+}
+
+MATCH NullExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
+	toChars(), type->toChars(), t->toChars(), committed);
+#endif
+    if (this->type->equals(t))
+	return MATCHexact;
+
+    /* Allow implicit conversions from invariant to mutable|const,
+     * and mutable to invariant. It works because, after all, a null
+     * doesn't actually point to anything.
+     */
+    if (t->invariantOf()->equals(type->invariantOf()))
+	return MATCHconst;
+
+    // NULL implicitly converts to any pointer type or dynamic array
+    if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
+    {
+	if (t->ty == Ttypedef)
+	    t = ((TypeTypedef *)t)->sym->basetype;
+	if (t->ty == Tpointer || t->ty == Tarray ||
+	    t->ty == Taarray  || t->ty == Tclass ||
+	    t->ty == Tdelegate)
+	    return committed ? MATCHconvert : MATCHexact;
+    }
+    return Expression::implicitConvTo(t);
+}
+
+#if DMDV2
+MATCH StructLiteralExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH m = Expression::implicitConvTo(t);
+    if (m != MATCHnomatch)
+	return m;
+    if (type->ty == t->ty && type->ty == Tstruct &&
+	((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
+    {
+	m = MATCHconst;
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    Type *te = e->type;
+	    if (t->mod == 0)
+		te = te->mutableOf();
+	    else
+	    {	assert(t->mod == MODinvariant);
+		te = te->invariantOf();
+	    }
+	    MATCH m2 = e->implicitConvTo(te);
+	    //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
+	    if (m2 < m)
+		m = m2;
+	}
+    }
+    return m;
+}
+#endif
+
+MATCH StringExp::implicitConvTo(Type *t)
+{   MATCH m;
+
+#if 0
+    printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
+	toChars(), committed, type->toChars(), t->toChars());
+#endif
+    if (!committed)
+    {
+    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+    {
+	return MATCHnomatch;
+    }
+    if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
+    {
+	TY tyn = type->nextOf()->ty;
+	if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
+	{   Type *tn;
+	    MATCH m;
+
+	    switch (t->ty)
+	    {
+		case Tsarray:
+		    if (type->ty == Tsarray)
+		    {
+			if (((TypeSArray *)type)->dim->toInteger() !=
+			    ((TypeSArray *)t)->dim->toInteger())
+			    return MATCHnomatch;
+			TY tynto = t->nextOf()->ty;
+			if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+			    return MATCHexact;
+		    }
+		case Tarray:
+		case Tpointer:
+		    tn = t->nextOf();
+		    m = MATCHexact;
+		    if (type->nextOf()->mod != tn->mod)
+		    {	if (!tn->isConst())
+			    return MATCHnomatch;
+			m = MATCHconst;
+		    }
+		    switch (tn->ty)
+		    {
+			case Tchar:
+			case Twchar:
+			case Tdchar:
+			    return m;
+		    }
+		    break;
+	    }
+	}
+    }
+    }
+    return Expression::implicitConvTo(t);
+#if 0
+    m = (MATCH)type->implicitConvTo(t);
+    if (m)
+    {
+	return m;
+    }
+
+    return MATCHnomatch;
+#endif
+}
+
+MATCH ArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+#if 0
+    printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		result = MATCHnomatch;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(tb->nextOf());
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray)
+    {
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)keys->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	    e = (Expression *)values->data[i];
+	    m = (MATCH)e->implicitConvTo(tb->nextOf());
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AddrExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+
+	t = t->toBasetype();
+
+	if (e1->op == TOKoverloadset &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{   OverExp *eo = (OverExp *)e1;
+	    FuncDeclaration *f = NULL;
+	    for (int i = 0; i < eo->vars->a.dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
+		FuncDeclaration *f2 = s->isFuncDeclaration();
+		assert(f2);
+		if (f2->overloadExactMatch(t->nextOf()))
+		{   if (f)
+			/* Error if match in more than one overload set,
+			 * even if one is a 'better' match than the other.
+			 */
+			ScopeDsymbol::multiplyDefined(loc, f, f2);
+		    else
+			f = f2;
+		    result = MATCHexact;
+		}
+	    }
+	}
+
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+// LDC: it happens for us
+#if !IN_LLVM
+	    /* I don't think this can ever happen -
+	     * it should have been
+	     * converted to a SymOffExp.
+	     */
+	    assert(0);
+#endif
+	    VarExp *ve = (VarExp *)e1;
+	    FuncDeclaration *f = ve->var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->nextOf()))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH SymOffExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {	f = f->overloadExactMatch(t->nextOf());
+		if (f)
+		{   if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
+			(t->ty == Tpointer && !(f->needThis() || f->isNested())))
+		    {
+			result = MATCHexact;
+		    }
+		}
+	    }
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH DelegateExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction &&
+	    t->ty == Tdelegate && t->nextOf()->ty == Tfunction)
+	{
+	    if (func && func->overloadExactMatch(t->nextOf()))
+		result = MATCHexact;
+	}
+    }
+    return result;
+}
+
+MATCH CondExp::implicitConvTo(Type *t)
+{
+    MATCH m1;
+    MATCH m2;
+
+    m1 = e1->implicitConvTo(t);
+    m2 = e2->implicitConvTo(t);
+
+    // Pick the worst match
+    return (m1 < m2) ? m1 : m2;
+}
+
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ */
+
+Expression *Expression::castTo(Scope *sc, Type *t)
+{
+    //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
+#if 0
+    printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t)
+	return this;
+    Expression *e = this;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Do (type *) cast of (type [dim])
+	if (tb->ty == Tpointer &&
+	    typeb->ty == Tsarray
+	   )
+	{
+	    //printf("Converting [dim] to *\n");
+
+	    if (typeb->size(loc) == 0)
+		e = new NullExp(loc);
+	    else
+		e = new AddrExp(loc, e);
+	}
+#if 0
+	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
+	{
+	    TypeDelegate *td = (TypeDelegate *)tb;
+	    TypeFunction *tf = (TypeFunction *)td->nextOf();
+	    return toDelegate(sc, tf->nextOf());
+	}
+#endif
+	else
+	{
+	    e = new CastExp(loc, e, tb);
+	}
+    }
+    else
+    {
+	e = e->copy();	// because of COW for assignment to e->type
+    }
+    assert(e != this);
+    e->type = t;
+    //printf("Returning: %s\n", e->toChars());
+    return e;
+}
+
+
+Expression *RealExp::castTo(Scope *sc, Type *t)
+{   Expression *e = this;
+    if (type != t)
+    {
+	if ((type->isreal() && t->isreal()) ||
+	    (type->isimaginary() && t->isimaginary())
+	   )
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+
+Expression *ComplexExp::castTo(Scope *sc, Type *t)
+{   Expression *e = this;
+    if (type != t)
+    {
+	if (type->iscomplex() && t->iscomplex())
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+
+Expression *NullExp::castTo(Scope *sc, Type *t)
+{   NullExp *e;
+    Type *tb;
+
+    //printf("NullExp::castTo(t = %p)\n", t);
+    if (type == t)
+    {
+	committed = 1;
+	return this;
+    }
+    e = (NullExp *)copy();
+    e->committed = 1;
+    tb = t->toBasetype();
+    e->type = type->toBasetype();
+    if (tb != e->type)
+    {
+	// NULL implicitly converts to any pointer type or dynamic array
+	if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
+	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
+	     tb->ty == Tdelegate))
+	{
+#if 0
+	    if (tb->ty == Tdelegate)
+	    {   TypeDelegate *td = (TypeDelegate *)tb;
+		TypeFunction *tf = (TypeFunction *)td->nextOf();
+
+		if (!tf->varargs &&
+		    !(tf->arguments && tf->arguments->dim)
+		   )
+		{
+		    return Expression::castTo(sc, t);
+		}
+	    }
+#endif
+	}
+	else
+	{
+	    return e->Expression::castTo(sc, t);
+	}
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *StringExp::castTo(Scope *sc, Type *t)
+{
+    /* This follows copy-on-write; any changes to 'this'
+     * will result in a copy.
+     * The this->string member is considered immutable.
+     */
+    StringExp *se;
+    Type *tb;
+    int copied = 0;
+
+    //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
+
+    if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+    {
+	error("cannot convert string literal to void*");
+    }
+
+    se = this;
+    if (!committed)
+    {   se = (StringExp *)copy();
+	se->committed = 1;
+	copied = 1;
+    }
+
+    if (type == t)
+    {
+	return se;
+    }
+
+    tb = t->toBasetype();
+    //printf("\ttype = %s\n", type->toChars());
+    if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
+	return Expression::castTo(sc, t);
+
+    Type *typeb = type->toBasetype();
+    if (typeb == tb)
+    {
+	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	se->type = t;
+	return se;
+    }
+
+    if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+    {	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	goto Lcast;
+    }
+    if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
+    {	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	goto Lcast;
+    }
+
+    if (typeb->nextOf()->size() == tb->nextOf()->size())
+    {
+	if (!copied)
+	{   se = (StringExp *)copy();
+	    copied = 1;
+	}
+	if (tb->ty == Tsarray)
+	    goto L2;	// handle possible change in static array dimension
+	se->type = t;
+	return se;
+    }
+
+    if (committed)
+	goto Lcast;
+
+#define X(tf,tt)	((tf) * 256 + (tt))
+    {
+    OutBuffer buffer;
+    size_t newlen = 0;
+    int tfty = typeb->nextOf()->toBasetype()->ty;
+    int ttty = tb->nextOf()->toBasetype()->ty;
+    switch (X(tfty, ttty))
+    {
+	case X(Tchar, Tchar):
+	case X(Twchar,Twchar):
+	case X(Tdchar,Tdchar):
+	    break;
+
+	case X(Tchar, Twchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF16(c);
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	case X(Tchar, Tdchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Twchar,Tchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF8(c);
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Twchar,Tdchar):
+	    for (size_t u = 0; u < len;)
+	    {	unsigned c;
+		const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Tdchar,Tchar):
+	    for (size_t u = 0; u < len; u++)
+	    {
+		unsigned c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF8(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Tdchar,Twchar):
+	    for (size_t u = 0; u < len; u++)
+	    {
+		unsigned c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF16(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	L1:
+	    if (!copied)
+	    {   se = (StringExp *)copy();
+		copied = 1;
+	    }
+	    se->string = buffer.extractData();
+	    se->len = newlen;
+	    se->sz = tb->nextOf()->size();
+	    break;
+
+	default:
+	    assert(typeb->nextOf()->size() != tb->nextOf()->size());
+	    goto Lcast;
+    }
+    }
+#undef X
+L2:
+    assert(copied);
+
+    // See if need to truncate or extend the literal
+    if (tb->ty == Tsarray)
+    {
+	int dim2 = ((TypeSArray *)tb)->dim->toInteger();
+
+	//printf("dim from = %d, to = %d\n", se->len, dim2);
+
+	// Changing dimensions
+	if (dim2 != se->len)
+	{
+	    // Copy when changing the string literal
+	    unsigned newsz = se->sz;
+	    void *s;
+	    int d;
+
+	    d = (dim2 < se->len) ? dim2 : se->len;
+	    s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
+	    memcpy(s, se->string, d * newsz);
+	    // Extend with 0, add terminating 0
+	    memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+	    se->string = s;
+	    se->len = dim2;
+	}
+    }
+    se->type = t;
+    return se;
+
+Lcast:
+    Expression *e = new CastExp(loc, se, t);
+    e->type = t;	// so semantic() won't be run on e
+    return e;
+}
+
+Expression *AddrExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+
+	if (e1->op == TOKoverloadset &&
+	    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+	{   OverExp *eo = (OverExp *)e1;
+	    FuncDeclaration *f = NULL;
+	    for (int i = 0; i < eo->vars->a.dim; i++)
+	    {   Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
+		FuncDeclaration *f2 = s->isFuncDeclaration();
+		assert(f2);
+		if (f2->overloadExactMatch(t->nextOf()))
+		{   if (f)
+			/* Error if match in more than one overload set,
+			 * even if one is a 'better' match than the other.
+			 */
+			ScopeDsymbol::multiplyDefined(loc, f, f2);
+		    else
+			f = f2;
+		}
+	    }
+	    if (f)
+	    {	f->tookAddressOf = 1;
+		SymOffExp *se = new SymOffExp(loc, f, 0, 0);
+		se->semantic(sc);
+		// Let SymOffExp::castTo() do the heavy lifting
+		return se->castTo(sc, t);
+	    }
+	}
+
+
+	if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    VarExp *ve = (VarExp *)e1;
+	    FuncDeclaration *f = ve->var->isFuncDeclaration();
+	    if (f)
+	    {
+// LDC: not in ldc
+#if !IN_LLVM
+		assert(0);	// should be SymOffExp instead
+#endif
+		f = f->overloadExactMatch(tb->nextOf());
+		if (f)
+		{
+		    e = new VarExp(loc, f);
+		    e->type = f->type;
+		    e = new AddrExp(loc, e);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+
+Expression *TupleExp::castTo(Scope *sc, Type *t)
+{   TupleExp *e = (TupleExp *)copy();
+    e->exps = (Expressions *)exps->copy();
+    for (size_t i = 0; i < e->exps->dim; i++)
+    {   Expression *ex = (Expression *)e->exps->data[i];
+	ex = ex->castTo(sc, t);
+	e->exps->data[i] = (void *)ex;
+    }
+    return e;
+}
+
+
+Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t)
+	return this;
+    ArrayLiteralExp *e = this;
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
+	// Not trying to convert non-void[] to void[]
+	!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		goto L1;
+	}
+
+	e = (ArrayLiteralExp *)copy();
+	e->elements = (Expressions *)elements->copy();
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *ex = (Expression *)elements->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->elements->data[i] = (void *)ex;
+	}
+	e->type = t;
+	return e;
+    }
+    if (tb->ty == Tpointer && typeb->ty == Tsarray)
+    {
+	e = (ArrayLiteralExp *)copy();
+	e->type = typeb->nextOf()->pointerTo();
+    }
+L1:
+    return e->Expression::castTo(sc, t);
+}
+
+Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    if (type == t)
+	return this;
+    AssocArrayLiteralExp *e = this;
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray &&
+	tb->nextOf()->toBasetype()->ty != Tvoid)
+    {
+	e = (AssocArrayLiteralExp *)copy();
+	e->keys = (Expressions *)keys->copy();
+	e->values = (Expressions *)values->copy();
+	assert(keys->dim == values->dim);
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *ex = (Expression *)values->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->values->data[i] = (void *)ex;
+
+	    ex = (Expression *)keys->data[i];
+	    ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
+	    e->keys->data[i] = (void *)ex;
+	}
+	e->type = t;
+	return e;
+    }
+L1:
+    return e->Expression::castTo(sc, t);
+}
+
+Expression *SymOffExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t && hasOverloads == 0)
+	return this;
+    Expression *e;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (hasOverloads &&
+	    typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
+	    (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->nextOf());
+		if (f)
+		{
+		    if (tb->ty == Tdelegate && f->needThis() && hasThis(sc))
+		    {
+			e = new DelegateExp(loc, new ThisExp(loc), f);
+			e = e->semantic(sc);
+		    }
+		    else if (tb->ty == Tdelegate && f->isNested())
+		    {
+			e = new DelegateExp(loc, new IntegerExp(0), f);
+			e = e->semantic(sc);
+		    }
+		    else
+		    {
+			e = new SymOffExp(loc, f, 0);
+			e->type = t;
+		    }
+		    f->tookAddressOf = 1;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	e = copy();
+	e->type = t;
+	((SymOffExp *)e)->hasOverloads = 0;
+    }
+    return e;
+}
+
+Expression *DelegateExp::castTo(Scope *sc, Type *t)
+{
+#if 0
+    printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    static char msg[] = "cannot form delegate due to covariant return type";
+
+    Expression *e = this;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
+    {
+	// Look for delegates to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction &&
+	    tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction)
+	{
+	    if (func)
+	    {
+		f = func->overloadExactMatch(tb->nextOf());
+		if (f)
+		{   int offset;
+		    if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
+			error("%s", msg);
+		    f->tookAddressOf = 1;
+		    e = new DelegateExp(loc, e1, f);
+		    e->type = t;
+		    return e;
+		}
+		if (func->tintro)
+		    error("%s", msg);
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	int offset;
+
+	func->tookAddressOf = 1;
+	if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset)
+	    error("%s", msg);
+	e = copy();
+	e->type = t;
+    }
+    return e;
+}
+
+Expression *CondExp::castTo(Scope *sc, Type *t)
+{
+    Expression *e = this;
+
+    if (type != t)
+    {
+	if (1 || e1->op == TOKstring || e2->op == TOKstring)
+	{   e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *BinExp::scaleFactor(Scope *sc)
+{   d_uns64 stride;
+    Type *t1b = e1->type->toBasetype();
+    Type *t2b = e2->type->toBasetype();
+
+    if (t1b->ty == Tpointer && t2b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (ptr + int) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+
+	stride = t1b->nextOf()->size(loc);
+	if (!t->equals(t2b))
+	    e2 = e2->castTo(sc, t);
+    // LDC: llvm uses typesafe pointer arithmetic
+    #if !IN_LLVM
+	e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
+    #endif
+	e2->type = t;
+	type = e1->type;
+    }
+    else if (t2b->ty == Tpointer && t1b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (int + ptr) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+	Expression *e;
+
+	stride = t2b->nextOf()->size(loc);
+	if (!t->equals(t1b))
+	    e = e1->castTo(sc, t);
+	else
+	    e = e1;
+    #if !IN_LLVM
+	e = new MulExp(loc, e, new IntegerExp(0, stride, t));
+    #endif
+	e->type = t;
+	type = e2->type;
+	e1 = e2;
+	e2 = e;
+    }
+    return this;
+}
+
+/**************************************
+ * Combine types.
+ * Output:
+ *	*pt	merged type, if *pt is not NULL
+ *	*pe1	rewritten e1
+ *	*pe2	rewritten e2
+ * Returns:
+ *	!=0	success
+ *	0	failed
+ */
+
+int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
+{
+    //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
+    //dump(0);
+
+    Expression *e1 = (*pe1)->integralPromotions(sc);
+    Expression *e2 = (*pe2)->integralPromotions(sc);
+
+    Type *t1 = e1->type;
+    Type *t2 = e2->type;
+    assert(t1);
+    Type *t = t1;
+
+    //if (t1) printf("\tt1 = %s\n", t1->toChars());
+    //if (t2) printf("\tt2 = %s\n", t2->toChars());
+#ifdef DEBUG
+    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
+#endif
+    assert(t2);
+
+    Type *t1b = t1->toBasetype();
+    Type *t2b = t2->toBasetype();
+
+    TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+    {	TY ty1;
+	TY ty2;
+
+	ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
+	ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
+
+	if (t1b->ty == ty1)	// if no promotions
+	{
+	    if (t1 == t2)
+	    {
+		t = t1;
+		goto Lret;
+	    }
+
+	    if (t1b == t2b)
+	    {
+		t = t1b;
+		goto Lret;
+	    }
+	}
+
+	t = Type::basic[ty];
+
+	t1 = Type::basic[ty1];
+	t2 = Type::basic[ty2];
+	e1 = e1->castTo(sc, t1);
+	e2 = e2->castTo(sc, t2);
+	//printf("after typeCombine():\n");
+	//dump(0);
+	//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+	goto Lret;
+    }
+
+    t1 = t1b;
+    t2 = t2b;
+
+Lagain:
+    if (t1 == t2)
+    {
+    }
+    else if (t1->ty == Tpointer && t2->ty == Tpointer)
+    {
+	// Bring pointers to compatible type
+	Type *t1n = t1->nextOf();
+	Type *t2n = t2->nextOf();
+
+	if (t1n == t2n)
+	    ;
+	else if (t1n->ty == Tvoid)	// pointers to void are always compatible
+	    t = t2;
+	else if (t2n->ty == Tvoid)
+	    ;
+	else if (t1n->mod != t2n->mod)
+	{
+	    t1 = t1n->mutableOf()->constOf()->pointerTo();
+	    t2 = t2n->mutableOf()->constOf()->pointerTo();
+	    t = t1;
+	    goto Lagain;
+	}
+	else if (t1n->ty == Tclass && t2n->ty == Tclass)
+	{   ClassDeclaration *cd1 = t1n->isClassHandle();
+	    ClassDeclaration *cd2 = t2n->isClassHandle();
+	    int offset;
+
+	    if (cd1->isBaseOf(cd2, &offset))
+	    {
+		if (offset)
+		    e2 = e2->castTo(sc, t);
+	    }
+	    else if (cd2->isBaseOf(cd1, &offset))
+	    {
+		t = t2;
+		if (offset)
+		    e1 = e1->castTo(sc, t);
+	    }
+	    else
+		goto Lincompatible;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+	     e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid)
+    {	/*  (T[n] op void*)
+	 *  (T[] op void*)
+	 */
+	goto Lx1;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+	     e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid)
+    {	/*  (void* op T[n])
+	 *  (void* op T[])
+	 */
+	goto Lx2;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    /* If one is mutable and the other invariant, then retry
+     * with both of them as const
+     */
+    else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
+	     (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
+	     t1->nextOf()->mod != t2->nextOf()->mod
+	    )
+    {
+	if (t1->ty == Tpointer)
+	    t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo();
+	else
+	    t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf();
+
+	if (t2->ty == Tpointer)
+	    t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo();
+	else
+	    t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf();
+	t = t1;
+	goto Lagain;
+    }
+    else if (t1->ty == Tclass || t2->ty == Tclass)
+    {
+	while (1)
+	{
+	    int i1 = e2->implicitConvTo(t1);
+	    int i2 = e1->implicitConvTo(t2);
+
+	    if (i1 && i2)
+	    {
+		// We have the case of class vs. void*, so pick class
+		if (t1->ty == Tpointer)
+		    i1 = 0;
+		else if (t2->ty == Tpointer)
+		    i2 = 0;
+	    }
+
+	    if (i2)
+	    {
+		goto Lt2;
+	    }
+	    else if (i1)
+	    {
+		goto Lt1;
+	    }
+	    else if (t1->ty == Tclass && t2->ty == Tclass)
+	    {	TypeClass *tc1 = (TypeClass *)t1;
+		TypeClass *tc2 = (TypeClass *)t2;
+
+		/* Pick 'tightest' type
+		 */
+		ClassDeclaration *cd1 = tc1->sym->baseClass;
+		ClassDeclaration *cd2 = tc2->sym->baseClass;
+
+		if (cd1 && cd2)
+		{   t1 = cd1->type;
+		    t2 = cd2->type;
+		}
+		else if (cd1)
+		    t1 = cd1->type;
+		else if (cd2)
+		    t2 = cd2->type;
+		else
+		    goto Lincompatible;
+	    }
+	    else
+		goto Lincompatible;
+	}
+    }
+    else if (t1->ty == Tstruct && t2->ty == Tstruct)
+    {
+	if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym)
+	    goto Lincompatible;
+    }
+    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e2->implicitConvTo(t1->nextOf()->arrayOf()))
+    {
+     Lx1:
+	t = t1->nextOf()->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e1->implicitConvTo(t2->nextOf()->arrayOf()))
+    {
+     Lx2:
+	t = t2->nextOf()->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->isintegral() && t2->isintegral())
+    {
+	assert(0);
+    }
+    else if (e1->op == TOKslice && t1->ty == Tarray &&
+	     e2->implicitConvTo(t1->nextOf()))
+    {	// T[] op T
+	e2 = e2->castTo(sc, t1->nextOf());
+	t = t1->nextOf()->arrayOf();
+    }
+    else if (e2->op == TOKslice && t2->ty == Tarray &&
+	     e1->implicitConvTo(t2->nextOf()))
+    {	// T op T[]
+	e1 = e1->castTo(sc, t2->nextOf());
+	t = t2->nextOf()->arrayOf();
+
+	//printf("test %s\n", e->toChars());
+	e1 = e1->optimize(WANTvalue);
+	if (e && e->isCommutative() && e1->isConst())
+	{   /* Swap operands to minimize number of functions generated
+	     */
+	    //printf("swap %s\n", e->toChars());
+	    Expression *tmp = e1;
+	    e1 = e2;
+	    e2 = tmp;
+	}
+    }
+    else
+    {
+     Lincompatible:
+	return 0;
+    }
+Lret:
+    if (!*pt)
+	*pt = t;
+    *pe1 = e1;
+    *pe2 = e2;
+#if 0
+    printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
+    if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
+    if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
+    printf("\ttype = %s\n", t->toChars());
+#endif
+    //dump(0);
+    return 1;
+
+
+Lt1:
+    e2 = e2->castTo(sc, t1);
+    t = t1;
+    goto Lret;
+
+Lt2:
+    e1 = e1->castTo(sc, t2);
+    t = t2;
+    goto Lret;
+}
+
+/************************************
+ * Bring leaves to common type.
+ */
+
+Expression *BinExp::typeCombine(Scope *sc)
+{
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+
+    if (op == TOKmin || op == TOKadd)
+    {
+	if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass))
+	    goto Lerror;
+    }
+
+    if (!typeMerge(sc, this, &type, &e1, &e2))
+	goto Lerror;
+    return this;
+
+Lerror:
+    incompatibleTypes();
+    type = Type::terror;
+    return this;
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *Expression::integralPromotions(Scope *sc)
+{
+    Expression *e = this;
+
+    //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
+    switch (type->toBasetype()->ty)
+    {
+	case Tvoid:
+	    error("void has no value");
+	    break;
+
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:
+	case Tbit:
+	case Tbool:
+	case Tchar:
+	case Twchar:
+	    e = e->castTo(sc, Type::tint32);
+	    break;
+
+	case Tdchar:
+	    e = e->castTo(sc, Type::tuns32);
+	    break;
+    }
+    return e;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/class.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,1420 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "init.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "mtype.h"
+#include "scope.h"
+#include "module.h"
+#include "expression.h"
+#include "statement.h"
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::classinfo;
+ClassDeclaration *ClassDeclaration::object;
+
+ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : AggregateDeclaration(loc, id)
+{
+    static char msg[] = "only object.d can define this reserved class name";
+
+    if (baseclasses)
+	this->baseclasses = *baseclasses;
+    baseClass = NULL;
+
+    interfaces_dim = 0;
+    interfaces = NULL;
+
+    vtblInterfaces = NULL;
+
+    //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim);
+
+    // For forward references
+    type = new TypeClass(this);
+    handle = type;
+
+    staticCtor = NULL;
+    staticDtor = NULL;
+
+    vtblsym = NULL;
+    vclassinfo = NULL;
+
+    if (id)
+    {	// Look for special class names
+
+	if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof)
+	    error("illegal class name");
+
+	// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+	if (id->toChars()[0] == 'T')
+	{
+	    if (id == Id::TypeInfo)
+	    {	if (Type::typeinfo)
+		    Type::typeinfo->error("%s", msg);
+		Type::typeinfo = this;
+	    }
+
+	    if (id == Id::TypeInfo_Class)
+	    {	if (Type::typeinfoclass)
+		    Type::typeinfoclass->error("%s", msg);
+		Type::typeinfoclass = this;
+	    }
+
+	    if (id == Id::TypeInfo_Interface)
+	    {	if (Type::typeinfointerface)
+		    Type::typeinfointerface->error("%s", msg);
+		Type::typeinfointerface = this;
+	    }
+
+	    if (id == Id::TypeInfo_Struct)
+	    {	if (Type::typeinfostruct)
+		    Type::typeinfostruct->error("%s", msg);
+		Type::typeinfostruct = this;
+	    }
+
+	    if (id == Id::TypeInfo_Typedef)
+	    {	if (Type::typeinfotypedef)
+		    Type::typeinfotypedef->error("%s", msg);
+		Type::typeinfotypedef = this;
+	    }
+
+	    if (id == Id::TypeInfo_Pointer)
+	    {	if (Type::typeinfopointer)
+		    Type::typeinfopointer->error("%s", msg);
+		Type::typeinfopointer = this;
+	    }
+
+	    if (id == Id::TypeInfo_Array)
+	    {	if (Type::typeinfoarray)
+		    Type::typeinfoarray->error("%s", msg);
+		Type::typeinfoarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_StaticArray)
+	    {	//if (Type::typeinfostaticarray)
+		    //Type::typeinfostaticarray->error("%s", msg);
+		Type::typeinfostaticarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_AssociativeArray)
+	    {	if (Type::typeinfoassociativearray)
+		    Type::typeinfoassociativearray->error("%s", msg);
+		Type::typeinfoassociativearray = this;
+	    }
+
+	    if (id == Id::TypeInfo_Enum)
+	    {	if (Type::typeinfoenum)
+		    Type::typeinfoenum->error("%s", msg);
+		Type::typeinfoenum = this;
+	    }
+
+	    if (id == Id::TypeInfo_Function)
+	    {	if (Type::typeinfofunction)
+		    Type::typeinfofunction->error("%s", msg);
+		Type::typeinfofunction = this;
+	    }
+
+	    if (id == Id::TypeInfo_Delegate)
+	    {	if (Type::typeinfodelegate)
+		    Type::typeinfodelegate->error("%s", msg);
+		Type::typeinfodelegate = this;
+	    }
+
+	    if (id == Id::TypeInfo_Tuple)
+	    {	if (Type::typeinfotypelist)
+		    Type::typeinfotypelist->error("%s", msg);
+		Type::typeinfotypelist = this;
+	    }
+
+#if DMDV2
+	    if (id == Id::TypeInfo_Const)
+	    {	if (Type::typeinfoconst)
+		    Type::typeinfoconst->error("%s", msg);
+		Type::typeinfoconst = this;
+	    }
+
+	    if (id == Id::TypeInfo_Invariant)
+	    {	if (Type::typeinfoinvariant)
+		    Type::typeinfoinvariant->error("%s", msg);
+		Type::typeinfoinvariant = this;
+	    }
+#endif
+	}
+
+	if (id == Id::Object)
+	{   if (object)
+		object->error("%s", msg);
+	    object = this;
+	}
+
+	if (id == Id::ClassInfo)
+	{   if (classinfo)
+		classinfo->error("%s", msg);
+	    classinfo = this;
+	}
+
+	if (id == Id::ModuleInfo)
+	{   if (Module::moduleinfo)
+		Module::moduleinfo->error("%s", msg);
+	    Module::moduleinfo = this;
+	}
+    }
+
+    com = 0;
+    isauto = 0;
+    isabstract = 0;
+    isnested = 0;
+    vthis = NULL;
+    inuse = 0;
+}
+
+Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
+    if (s)
+	cd = (ClassDeclaration *)s;
+    else
+	cd = new ClassDeclaration(loc, ident, NULL);
+
+    cd->storage_class |= storage_class;
+
+    cd->baseclasses.setDim(this->baseclasses.dim);
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)this->baseclasses.data[i];
+	BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
+	cd->baseclasses.data[i] = b2;
+    }
+
+    ScopeDsymbol::syntaxCopy(cd);
+    return cd;
+}
+
+void ClassDeclaration::semantic(Scope *sc)
+{   int i;
+    unsigned offset;
+
+    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
+    //printf("sc->stc = %x\n", sc->stc);
+
+    //{ static int n;  if (++n == 20) *(char*)0=0; }
+
+    if (!ident)		// if anonymous class
+    {	const char *id = "__anonclass";
+
+	ident = Identifier::generateId(id);
+    }
+
+    if (!scope)
+    {
+	if (!parent && sc->parent && !sc->parent->isModule())
+	    parent = sc->parent;
+
+	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tclass '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)
+    {	if (!scope)
+	{   //printf("\tsemantic for '%s' is already completed\n", toChars());
+	    return;		// semantic() already completed
+	}
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+#ifdef IN_GCC
+    methods.setDim(0);
+#endif
+
+    if (sc->stc & STCdeprecated)
+    {
+	isdeprecated = 1;
+    }
+
+    if (sc->linkage == LINKcpp)
+	error("cannot create C++ classes");
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    // See if there's a base class as first in baseclasses[]
+    if (baseclasses.dim)
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[0];
+	//b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty != Tclass)
+	{   error("base type must be class or interface, not %s", b->type->toChars());
+	    baseclasses.remove(0);
+	}
+	else
+	{
+	    tc = (TypeClass *)(tb);
+
+	    if (tc->sym->isDeprecated())
+	    {
+		if (!isDeprecated())
+		{
+		    // Deriving from deprecated class makes this one deprecated too
+		    isdeprecated = 1;
+
+		    tc->checkDeprecated(loc, sc);
+		}
+	    }
+
+	    if (tc->sym->isInterfaceDeclaration())
+		;
+	    else
+	    {
+		for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+		{
+		    if (cdb == this)
+		    {
+			error("circular inheritance");
+			baseclasses.remove(0);
+			goto L7;
+		    }
+		}
+		if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0)
+		{
+		    //error("forward reference of base class %s", baseClass->toChars());
+		    // Forward reference of base class, try again later
+		    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+		    scope = scx ? scx : new Scope(*sc);
+		    scope->setNoFree();
+		    scope->module->addDeferredSemantic(this);
+		    return;
+		}
+		else
+		{   baseClass = tc->sym;
+		    b->base = baseClass;
+		}
+	     L7: ;
+	    }
+	}
+    }
+
+    // Treat the remaining entries in baseclasses as interfaces
+    // Check for errors, handle forward references
+    for (i = (baseClass ? 1 : 0); i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    if (tc->sym->isDeprecated())
+	    {
+		if (!isDeprecated())
+		{
+		    // Deriving from deprecated class makes this one deprecated too
+		    isdeprecated = 1;
+
+		    tc->checkDeprecated(loc, sc);
+		}
+	    }
+
+	    // Check for duplicate interfaces
+	    for (size_t j = (baseClass ? 1 : 0); j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (!b->base->symtab || b->base->scope)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+	i++;
+    }
+
+
+    // If no base class, and this is not an Object, use Object as base class
+    if (!baseClass && ident != Id::Object)
+    {
+	// BUG: what if Object is redefined in an inner scope?
+	Type *tbase = new TypeIdentifier(0, Id::Object);
+	BaseClass *b;
+	TypeClass *tc;
+	Type *bt;
+
+	if (!object)
+	{
+	    error("missing or corrupt object.d");
+	    fatal();
+	}
+	bt = tbase->semantic(loc, sc)->toBasetype();
+	b = new BaseClass(bt, PROTpublic);
+	baseclasses.shift(b);
+	assert(b->type->ty == Tclass);
+	tc = (TypeClass *)(b->type);
+	baseClass = tc->sym;
+	assert(!baseClass->isInterfaceDeclaration());
+	b->base = baseClass;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+
+    if (baseClass)
+    {
+	if (baseClass->storage_class & STCfinal)
+	    error("cannot inherit from final class %s", baseClass->toChars());
+
+	interfaces_dim--;
+	interfaces++;
+
+	// Copy vtbl[] from base class
+	vtbl.setDim(baseClass->vtbl.dim);
+	memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim);
+
+	// Inherit properties from base class
+	com = baseClass->isCOMclass();
+	isauto = baseClass->isauto;
+	vthis = baseClass->vthis;
+	storage_class |= baseClass->storage_class & (STCconst | STCinvariant);
+    }
+    else
+    {
+	// No base class, so this is the root of the class hierarchy
+	vtbl.setDim(0);
+	vtbl.push(this);		// leave room for classinfo as first member
+    }
+
+    protection = sc->protection;
+    storage_class |= sc->stc;
+
+    if (sizeok == 0)
+    {
+	interfaceSemantic(sc);
+
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->addMember(sc, this, 1);
+	}
+
+	/* If this is a nested class, add the hidden 'this'
+	 * member which is a pointer to the enclosing scope.
+	 */
+	if (vthis)		// if inheriting from nested class
+	{   // Use the base class's 'this' member
+	    isnested = 1;
+	    if (storage_class & STCstatic)
+		error("static class cannot inherit from nested class %s", baseClass->toChars());
+	    if (toParent2() != baseClass->toParent2())
+	    {
+		if (toParent2())
+		{
+		    error("is nested within %s, but super class %s is nested within %s",
+			toParent2()->toChars(),
+			baseClass->toChars(),
+			baseClass->toParent2()->toChars());
+		}
+		else
+		{
+		    error("is not nested, but super class %s is nested within %s",
+			baseClass->toChars(),
+			baseClass->toParent2()->toChars());
+		}
+		isnested = 0;
+	    }
+	}
+	else if (!(storage_class & STCstatic))
+	{   Dsymbol *s = toParent2();
+	    if (s)
+	    {
+		ClassDeclaration *cd = s->isClassDeclaration();
+		FuncDeclaration *fd = s->isFuncDeclaration();
+
+
+		if (cd || fd)
+		{   isnested = 1;
+		    Type *t;
+		    if (cd)
+			t = cd->type;
+		    else if (fd)
+		    {	AggregateDeclaration *ad = fd->isMember2();
+			if (ad)
+			    t = ad->handle;
+			else
+			{
+			    t = new TypePointer(Type::tvoid);
+			    t = t->semantic(0, sc);
+			}
+		    }
+		    else
+			assert(0);
+		    assert(!vthis);
+		    vthis = new ThisDeclaration(t);
+		    members->push(vthis);
+		}
+	    }
+	}
+    }
+
+    if (storage_class & (STCauto | STCscope))
+	isauto = 1;
+    if (storage_class & STCabstract)
+	isabstract = 1;
+    if (storage_class & STCinvariant)
+	type = type->invariantOf();
+    else if (storage_class & STCconst)
+	type = type->constOf();
+
+    sc = sc->push(this);
+    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
+		 STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
+    sc->stc |= storage_class & (STCconst | STCinvariant);
+    sc->parent = this;
+    sc->inunion = 0;
+
+    if (isCOMclass())
+	sc->linkage = LINKwindows;
+    sc->protection = PROTpublic;
+    sc->explicitProtection = 0;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    if (baseClass)
+    {	sc->offset = baseClass->structsize;
+	alignsize = baseClass->alignsize;
+//	if (isnested)
+//	    sc->offset += PTRSIZE;	// room for uplevel context pointer
+    }
+    else
+    {	sc->offset = PTRSIZE * 2;	// allow room for __vptr and __monitor
+	alignsize = 4;
+    }
+    structsize = sc->offset;
+    Scope scsave = *sc;
+    int members_dim = members->dim;
+    sizeok = 0;
+    for (i = 0; i < members_dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+
+    if (sizeok == 2)
+    {	// semantic() failed because of forward references.
+	// Unwind what we did, and defer it for later
+	fields.setDim(0);
+	structsize = 0;
+	alignsize = 0;
+	structalign = 0;
+
+	sc = sc->pop();
+
+	scope = scx ? scx : new Scope(*sc);
+	scope->setNoFree();
+	scope->module->addDeferredSemantic(this);
+
+	//printf("\tsemantic('%s') failed due to forward references\n", toChars());
+	return;
+    }
+
+    //printf("\tsemantic('%s') successful\n", toChars());
+
+    structsize = sc->offset;
+    //members->print();
+
+    /* Look for special member functions.
+     * They must be in this class, not in a base class.
+     */
+    ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
+    if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration()))
+	ctor = NULL;
+
+//    dtor = (DtorDeclaration *)search(Id::dtor, 0);
+//    if (dtor && dtor->toParent() != this)
+//	dtor = NULL;
+
+//    inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
+//    if (inv && inv->toParent() != this)
+//	inv = NULL;
+
+    // Can be in base class
+    aggNew    = (NewDeclaration *)search(0, Id::classNew, 0);
+    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
+
+    // If this class has no constructor, but base class does, create
+    // a constructor:
+    //    this() { }
+    if (!ctor && baseClass && baseClass->ctor)
+    {
+	//printf("Creating default this(){} for class %s\n", toChars());
+	ctor = new CtorDeclaration(loc, 0, NULL, 0);
+	ctor->fbody = new CompoundStatement(0, new Statements());
+	members->push(ctor);
+	ctor->addMember(sc, this, 1);
+	*sc = scsave;	// why? What about sc->nofree?
+	sc->offset = structsize;
+	ctor->semantic(sc);
+	defaultCtor = ctor;
+    }
+
+#if 0
+    if (baseClass)
+    {	if (!aggDelete)
+	    aggDelete = baseClass->aggDelete;
+	if (!aggNew)
+	    aggNew = baseClass->aggNew;
+    }
+#endif
+
+    // Allocate instance of each new interface
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+	unsigned thissize = PTRSIZE;
+
+	alignmember(structalign, thissize, &sc->offset);
+	assert(b->offset == 0);
+	b->offset = sc->offset;
+
+	// Take care of single inheritance offsets
+	while (b->baseInterfaces_dim)
+	{
+	    b = &b->baseInterfaces[0];
+	    b->offset = sc->offset;
+	}
+
+	sc->offset += thissize;
+	if (alignsize < thissize)
+	    alignsize = thissize;
+    }
+    structsize = sc->offset;
+    sizeok = 1;
+    Module::dprogress++;
+
+    dtor = buildDtor(sc);
+
+    sc->pop();
+
+#if 0 // Do not call until toObjfile() because of forward references
+    // Fill in base class vtbl[]s
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+
+	//b->fillVtbl(this, &b->vtbl, 1);
+    }
+#endif
+    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (!isAnonymous())
+    {
+	buf->printf("%s ", kind());
+	buf->writestring(toChars());
+	if (baseclasses.dim)
+	    buf->writestring(" : ");
+    }
+    for (int i = 0; i < baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	if (i)
+	    buf->writeByte(',');
+	//buf->writestring(b->base->ident->toChars());
+	b->type->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+
+	buf->writestring("    ");
+	s->toCBuffer(buf, hgs);
+    }
+    buf->writestring("}");
+    buf->writenl();
+}
+
+#if 0
+void ClassDeclaration::defineRef(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    AggregateDeclaration::defineRef(s);
+    cd = s->isClassDeclaration();
+    baseType = cd->baseType;
+    cd->baseType = NULL;
+}
+#endif
+
+/*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+
+int ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
+{
+    if (!cd)
+	return 0;
+    //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {	BaseClass *b = (BaseClass *)cd->baseclasses.data[i];
+
+	if (b->base == this || isBaseOf2(b->base))
+	    return 1;
+    }
+    return 0;
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+
+int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    if (poffset)
+	*poffset = 0;
+    while (cd)
+    {
+	if (this == cd->baseClass)
+	    return 1;
+
+	/* cd->baseClass might not be set if cd is forward referenced.
+	 */
+	if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
+	{
+	    cd->error("base class is forward referenced by %s", toChars());
+	}
+
+	cd = cd->baseClass;
+    }
+    return 0;
+}
+
+Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s;
+
+    //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
+    if (scope)
+	semantic(scope);
+
+    if (!members || !symtab || scope)
+    {	error("is forward referenced when looking for '%s'", ident->toChars());
+	//*(char*)0=0;
+	return NULL;
+    }
+
+    s = ScopeDsymbol::search(loc, ident, flags);
+    if (!s)
+    {
+	// Search bases classes in depth-first, left to right order
+
+	int i;
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{
+	    BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    if (b->base)
+	    {
+		if (!b->base->symtab)
+		    error("base %s is forward referenced", b->base->ident->toChars());
+		else
+		{
+		    s = b->base->search(loc, ident, flags);
+		    if (s == this)	// happens if s is nested in this and derives from this
+			s = NULL;
+		    else if (s)
+			break;
+		}
+	    }
+	}
+    }
+    return s;
+}
+
+/**********************************************************
+ * fd is in the vtbl[] for this class.
+ * Return 1 if function is hidden (not findable through search).
+ */
+
+#if DMDV2
+int isf(void *param, FuncDeclaration *fd)
+{
+    //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
+    return param == fd;
+}
+
+int ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
+{
+    //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars());
+    Dsymbol *s = search(0, fd->ident, 4|2);
+    if (!s)
+    {	//printf("not found\n");
+	/* Because, due to a hack, if there are multiple definitions
+	 * of fd->ident, NULL is returned.
+	 */
+	return 0;
+    }
+    s = s->toAlias();
+    OverloadSet *os = s->isOverloadSet();
+    if (os)
+    {
+	for (int i = 0; i < os->a.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)os->a.data[i];
+	    FuncDeclaration *f2 = s->isFuncDeclaration();
+	    if (f2 && overloadApply(f2, &isf, fd))
+		return 0;
+	}
+	return 1;
+    }
+    else
+    {
+	FuncDeclaration *fdstart = s->isFuncDeclaration();
+	//printf("%s fdstart = %p\n", s->kind(), fdstart);
+	return !overloadApply(fdstart, &isf, fd);
+    }
+}
+#endif
+
+/****************
+ * Find virtual function matching identifier and type.
+ * Used to build virtual function tables for interface implementations.
+ */
+
+FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
+{
+    //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
+
+    ClassDeclaration *cd = this;
+    Array *vtbl = &cd->vtbl;
+    while (1)
+    {
+	for (size_t i = 0; i < vtbl->dim; i++)
+	{
+	    FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i];
+
+	    //printf("\t[%d] = %s\n", i, fd->toChars());
+	    if (ident == fd->ident &&
+		//tf->equals(fd->type)
+		fd->type->covariant(tf) == 1
+	       )
+	    {   //printf("\t\tfound\n");
+		return fd;
+	    }
+	    //else printf("\t\t%d\n", fd->type->covariant(tf));
+	}
+	if (!cd)
+	    break;
+	vtbl = &cd->vtblFinal;
+	cd = cd->baseClass;
+    }
+
+    return NULL;
+}
+
+void ClassDeclaration::interfaceSemantic(Scope *sc)
+{
+    InterfaceDeclaration *id = isInterfaceDeclaration();
+
+    vtblInterfaces = new BaseClasses();
+    vtblInterfaces->reserve(interfaces_dim);
+
+    for (size_t i = 0; i < interfaces_dim; i++)
+    {
+	BaseClass *b = interfaces[i];
+
+	// If this is an interface, and it derives from a COM interface,
+	// then this is a COM interface too.
+	if (b->base->isCOMinterface())
+	    com = 1;
+
+	if (b->base->isCPPinterface() && id)
+	    id->cpp = 1;
+
+	vtblInterfaces->push(b);
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+}
+
+/****************************************
+ */
+
+int ClassDeclaration::isCOMclass()
+{
+    return com;
+}
+
+int ClassDeclaration::isCOMinterface()
+{
+    return 0;
+}
+
+int ClassDeclaration::isCPPinterface()
+{
+    return 0;
+}
+
+
+/****************************************
+ */
+
+int ClassDeclaration::isAbstract()
+{
+    if (isabstract)
+	return TRUE;
+    for (int i = 1; i < vtbl.dim; i++)
+    {
+	FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration();
+
+	//printf("\tvtbl[%d] = %p\n", i, fd);
+	if (!fd || fd->isAbstract())
+	{
+	    isabstract |= 1;
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+
+/****************************************
+ * Returns !=0 if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing class or function)
+ */
+
+int ClassDeclaration::isNested()
+{
+    return isnested;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int ClassDeclaration::vtblOffset()
+{
+    return 1;
+}
+
+/****************************************
+ */
+
+const char *ClassDeclaration::kind()
+{
+    return "class";
+}
+
+/****************************************
+ */
+
+void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    aclasses->push(this);
+}
+
+/********************************* InterfaceDeclaration ****************************/
+
+InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : ClassDeclaration(loc, id, baseclasses)
+{
+    com = 0;
+    cpp = 0;
+    if (id == Id::IUnknown)	// IUnknown is the root of all COM interfaces
+    {	com = 1;
+	cpp = 1;		// IUnknown is also a C++ interface
+    }
+}
+
+Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
+{
+    InterfaceDeclaration *id;
+
+    if (s)
+	id = (InterfaceDeclaration *)s;
+    else
+	id = new InterfaceDeclaration(loc, ident, NULL);
+
+    ClassDeclaration::syntaxCopy(id);
+    return id;
+}
+
+void InterfaceDeclaration::semantic(Scope *sc)
+{   int i;
+
+    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+    if (inuse)
+	return;
+    if (!scope)
+    {	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tinterface '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)			// if already done
+    {	if (!scope)
+	    return;
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    if (sc->stc & STCdeprecated)
+    {
+	isdeprecated = 1;
+    }
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[0];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    if (!baseclasses.dim && sc->linkage == LINKcpp)
+	cpp = 1;
+
+    // Check for errors, handle forward references
+    for (i = 0; i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    // Check for duplicate interfaces
+	    for (size_t j = 0; j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (b->base == this || isBaseOf2(b->base))
+	    {
+		error("circular inheritance of interface");
+		baseclasses.remove(i);
+		continue;
+	    }
+	    if (!b->base->symtab || b->base->scope || b->base->inuse)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", b->base->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+#if 0
+	// Inherit const/invariant from base class
+	storage_class |= b->base->storage_class & (STCconst | STCinvariant);
+#endif
+	i++;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+    interfaceSemantic(sc);
+
+    if (vtblOffset())
+	vtbl.push(this);		// leave room at vtbl[0] for classinfo
+
+    // Cat together the vtbl[]'s from base interfaces
+    for (i = 0; i < interfaces_dim; i++)
+    {	BaseClass *b = interfaces[i];
+
+	// Skip if b has already appeared
+	for (int k = 0; k < i; k++)
+	{
+	    if (b == interfaces[i])
+		goto Lcontinue;
+	}
+
+	// Copy vtbl[] from base class
+	if (b->base->vtblOffset())
+	{   int d = b->base->vtbl.dim;
+	    if (d > 1)
+	    {
+		vtbl.reserve(d - 1);
+		for (int j = 1; j < d; j++)
+		    vtbl.push(b->base->vtbl.data[j]);
+	    }
+	}
+	else
+	{
+	    vtbl.append(&b->base->vtbl);
+	}
+
+      Lcontinue:
+	;
+    }
+
+    protection = sc->protection;
+    storage_class |= sc->stc & (STCconst | STCinvariant);
+
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->addMember(sc, this, 1);
+    }
+
+    sc = sc->push(this);
+    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
+                 STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls);
+    sc->stc |= storage_class & (STCconst | STCinvariant);
+    sc->parent = this;
+    if (isCOMinterface())
+	sc->linkage = LINKwindows;
+    else if (isCPPinterface())
+	sc->linkage = LINKcpp;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    sc->offset = PTRSIZE * 2;
+    inuse++;
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+    inuse--;
+    //members->print();
+    sc->pop();
+    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ * (Actually, if it is an interface supported by cd)
+ * Output:
+ *	*poffset	offset to start of class
+ *			OFFSET_RUNTIME	must determine offset at runtime
+ * Returns:
+ *	0	not a base
+ *	1	is a base
+ */
+
+int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    unsigned j;
+
+    //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
+    assert(!baseClass);
+    for (j = 0; j < cd->interfaces_dim; j++)
+    {
+	BaseClass *b = cd->interfaces[j];
+
+	//printf("\tbase %s\n", b->base->toChars());
+	if (this == b->base)
+	{
+	    //printf("\tfound at offset %d\n", b->offset);
+	    if (poffset)
+	    {	*poffset = b->offset;
+		if (j && cd->isInterfaceDeclaration())
+		    *poffset = OFFSET_RUNTIME;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{   if (j && poffset && cd->isInterfaceDeclaration())
+		*poffset = OFFSET_RUNTIME;
+	    return 1;
+	}
+    }
+
+    if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
+	return 1;
+
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+
+int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
+{
+    //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
+    for (unsigned j = 0; j < bc->baseInterfaces_dim; j++)
+    {
+	BaseClass *b = &bc->baseInterfaces[j];
+
+	if (this == b->base)
+	{
+	    if (poffset)
+	    {	*poffset = b->offset;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{
+	    return 1;
+	}
+    }
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the ClassInfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int InterfaceDeclaration::vtblOffset()
+{
+    if (isCOMinterface() || isCPPinterface())
+	return 0;
+    return 1;
+}
+
+int InterfaceDeclaration::isCOMinterface()
+{
+    return com;
+}
+
+int InterfaceDeclaration::isCPPinterface()
+{
+    return cpp;
+}
+
+/*******************************************
+ */
+
+const char *InterfaceDeclaration::kind()
+{
+    return "interface";
+}
+
+
+/******************************** BaseClass *****************************/
+
+BaseClass::BaseClass()
+{
+    memset(this, 0, sizeof(BaseClass));
+}
+
+BaseClass::BaseClass(Type *type, enum PROT protection)
+{
+    //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
+    this->type = type;
+    this->protection = protection;
+    base = NULL;
+    offset = 0;
+
+    baseInterfaces_dim = 0;
+    baseInterfaces = NULL;
+}
+
+/****************************************
+ * Fill in vtbl[] for base class based on member functions of class cd.
+ * Input:
+ *	vtbl		if !=NULL, fill it in
+ *	newinstance	!=0 means all entries must be filled in by members
+ *			of cd, not members of any base classes of cd.
+ * Returns:
+ *	!=0 if any entries were filled in by members of cd (not exclusively
+ *	by base classes)
+ */
+
+int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance)
+{
+    ClassDeclaration *id = base;
+    int j;
+    int result = 0;
+
+    //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
+    if (vtbl)
+	vtbl->setDim(base->vtbl.dim);
+
+    // first entry is ClassInfo reference
+    for (j = base->vtblOffset(); j < base->vtbl.dim; j++)
+    {
+	FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration();
+	FuncDeclaration *fd;
+	TypeFunction *tf;
+
+	//printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
+
+	assert(ifd);
+	// Find corresponding function in this class
+	tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
+	fd = cd->findFunc(ifd->ident, tf);
+	if (fd && !fd->isAbstract())
+	{
+	    //printf("            found\n");
+	    // Check that calling conventions match
+	    if (fd->linkage != ifd->linkage)
+		fd->error("linkage doesn't match interface function");
+
+	    // Check that it is current
+	    if (newinstance &&
+		fd->toParent() != cd &&
+		ifd->toParent() == base)
+		cd->error("interface function %s.%s is not implemented",
+		    id->toChars(), ifd->ident->toChars());
+
+	    if (fd->toParent() == cd)
+		result = 1;
+	}
+	else
+	{
+	    //printf("            not found\n");
+	    // BUG: should mark this class as abstract?
+	    if (!cd->isAbstract())
+		cd->error("interface function %s.%s isn't implemented",
+		    id->toChars(), ifd->ident->toChars());
+	    fd = NULL;
+	}
+	if (vtbl)
+	    vtbl->data[j] = fd;
+    }
+
+    return result;
+}
+
+void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
+{
+    //printf("+copyBaseInterfaces(), %s\n", base->toChars());
+//    if (baseInterfaces_dim)
+//	return;
+
+    baseInterfaces_dim = base->interfaces_dim;
+    baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass));
+
+    //printf("%s.copyBaseInterfaces()\n", base->toChars());
+    for (int i = 0; i < baseInterfaces_dim; i++)
+    {
+	BaseClass *b = &baseInterfaces[i];
+	BaseClass *b2 = base->interfaces[i];
+
+	assert(b2->vtbl.dim == 0);	// should not be filled yet
+	memcpy(b, b2, sizeof(BaseClass));
+
+	if (i)				// single inheritance is i==0
+	    vtblInterfaces->push(b);	// only need for M.I.
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+    //printf("-copyBaseInterfaces\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/clone.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,423 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "statement.h"
+#include "init.h"
+
+
+/*******************************************
+ * We need an opAssign for the struct if
+ * it has a destructor or a postblit.
+ * We need to generate one if a user-specified one does not exist.
+ */
+
+int StructDeclaration::needOpAssign()
+{
+#define X 0
+    if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
+    if (hasIdentityAssign)
+	goto Ldontneed;
+
+    if (dtor || postblit)
+	goto Lneed;
+
+    /* If any of the fields need an opAssign, then we
+     * need it too.
+     */
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v && v->storage_class & STCfield);
+	Type *tv = v->type->toBasetype();
+	while (tv->ty == Tsarray)
+	{   TypeSArray *ta = (TypeSArray *)tv;
+	    tv = tv->nextOf()->toBasetype();
+	}
+	if (tv->ty == Tstruct)
+	{   TypeStruct *ts = (TypeStruct *)tv;
+	    StructDeclaration *sd = ts->sym;
+	    if (sd->needOpAssign())
+		goto Lneed;
+	}
+    }
+Ldontneed:
+    if (X) printf("\tdontneed\n");
+    return 0;
+
+Lneed:
+    if (X) printf("\tneed\n");
+    return 1;
+#undef X
+}
+
+/******************************************
+ * Build opAssign for struct.
+ *	S* opAssign(S s) { ... }
+ */
+
+FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
+{
+    if (!needOpAssign())
+	return NULL;
+
+    //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
+
+    FuncDeclaration *fop = NULL;
+
+    Argument *param = new Argument(STCnodtor, type, Id::p, NULL);
+    Arguments *fparams = new Arguments;
+    fparams->push(param);
+    Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
+
+    fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype);
+
+    Expression *e = NULL;
+    if (postblit)
+    {	/* Swap:
+	 *    tmp = *this; *this = s; tmp.dtor();
+	 */
+	//printf("\tswap copy\n");
+	Identifier *idtmp = Lexer::uniqueId("__tmp");
+	VarDeclaration *tmp;
+	AssignExp *ec = NULL;
+	if (dtor)
+	{
+	    tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
+	    tmp->noauto = 1;
+	    e = new DeclarationExp(0, tmp);
+	    ec = new AssignExp(0,
+		new VarExp(0, tmp),
+		new PtrExp(0, new ThisExp(0)));
+	    ec->op = TOKblit;
+	    e = Expression::combine(e, ec);
+	}
+	ec = new AssignExp(0,
+		new PtrExp(0, new ThisExp(0)),
+		new IdentifierExp(0, Id::p));
+	ec->op = TOKblit;
+	e = Expression::combine(e, ec);
+	if (dtor)
+	{
+	    /* Instead of running the destructor on s, run it
+	     * on tmp. This avoids needing to copy tmp back in to s.
+	     */
+	    Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
+	    ec = new CallExp(0, ec);
+	    e = Expression::combine(e, ec);
+	}
+    }
+    else
+    {	/* Do memberwise copy
+	 */
+	//printf("\tmemberwise copy\n");
+	for (size_t i = 0; i < fields.dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v && v->storage_class & STCfield);
+	    // this.v = s.v;
+	    AssignExp *ec = new AssignExp(0,
+		new DotVarExp(0, new ThisExp(0), v, 0),
+		new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
+	    ec->op = TOKblit;
+	    e = Expression::combine(e, ec);
+	}
+    }
+    Statement *s1 = new ExpStatement(0, e);
+
+    /* Add:
+     *   return this;
+     */
+    e = new ThisExp(0);
+    Statement *s2 = new ReturnStatement(0, e);
+
+    fop->fbody = new CompoundStatement(0, s1, s2);
+
+    members->push(fop);
+    fop->addMember(sc, this, 1);
+
+    sc = sc->push();
+    sc->stc = 0;
+    sc->linkage = LINKd;
+
+    fop->semantic(sc);
+
+    sc->pop();
+
+    //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
+
+    return fop;
+}
+
+/*******************************************
+ * Build copy constructor for struct.
+ * Copy constructors are compiler generated only, and are only
+ * callable from the compiler. They are not user accessible.
+ * A copy constructor is:
+ *    void cpctpr(ref S s)
+ *    {
+ *	*this = s;
+ *	this.postBlit();
+ *    }
+ * This is done so:
+ *	- postBlit() never sees uninitialized data
+ *	- memcpy can be much more efficient than memberwise copy
+ *	- no fields are overlooked
+ */
+
+FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
+{
+    //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
+    FuncDeclaration *fcp = NULL;
+
+    /* Copy constructor is only necessary if there is a postblit function,
+     * otherwise the code generator will just do a bit copy.
+     */
+    if (postblit)
+    {
+	//printf("generating cpctor\n");
+
+	Argument *param = new Argument(STCref, type, Id::p, NULL);
+	Arguments *fparams = new Arguments;
+	fparams->push(param);
+	Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd);
+
+	fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype);
+
+	// Build *this = p;
+	Expression *e = new ThisExp(0);
+	e = new PtrExp(0, e);
+	AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
+	ea->op = TOKblit;
+	Statement *s = new ExpStatement(0, ea);
+
+	// Build postBlit();
+	e = new VarExp(0, postblit, 0);
+	e = new CallExp(0, e);
+
+	s = new CompoundStatement(0, s, new ExpStatement(0, e));
+	fcp->fbody = s;
+
+	members->push(fcp);
+
+	sc = sc->push();
+	sc->stc = 0;
+	sc->linkage = LINKd;
+
+	fcp->semantic(sc);
+
+	sc->pop();
+    }
+
+    return fcp;
+}
+
+/*****************************************
+ * Create inclusive postblit for struct by aggregating
+ * all the postblits in postblits[] with the postblits for
+ * all the members.
+ * Note the close similarity with AggregateDeclaration::buildDtor(),
+ * and the ordering changes (runs forward instead of backwards).
+ */
+
+#if DMDV2
+FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
+{
+    //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
+    Expression *e = NULL;
+
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v && v->storage_class & STCfield);
+	Type *tv = v->type->toBasetype();
+	size_t dim = 1;
+	while (tv->ty == Tsarray)
+	{   TypeSArray *ta = (TypeSArray *)tv;
+	    dim *= ((TypeSArray *)tv)->dim->toInteger();
+	    tv = tv->nextOf()->toBasetype();
+	}
+	if (tv->ty == Tstruct)
+	{   TypeStruct *ts = (TypeStruct *)tv;
+	    StructDeclaration *sd = ts->sym;
+	    if (sd->postblit)
+	    {	Expression *ex;
+
+		// this.v
+		ex = new ThisExp(0);
+		ex = new DotVarExp(0, ex, v, 0);
+
+		if (dim == 1)
+		{   // this.v.dtor()
+		    ex = new DotVarExp(0, ex, sd->postblit, 0);
+		    ex = new CallExp(0, ex);
+		}
+		else
+		{
+		    // Typeinfo.postblit(cast(void*)&this.v);
+		    Expression *ea = new AddrExp(0, ex);
+		    ea = new CastExp(0, ea, Type::tvoid->pointerTo());
+
+		    Expression *et = v->type->getTypeInfo(sc);
+		    et = new DotIdExp(0, et, Id::postblit);
+
+		    ex = new CallExp(0, et, ea);
+		}
+		e = Expression::combine(e, ex);	// combine in forward order
+	    }
+	}
+    }
+
+    /* Build our own "postblit" which executes e
+     */
+    if (e)
+    {	//printf("Building __fieldPostBlit()\n");
+	PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit"));
+	dd->fbody = new ExpStatement(0, e);
+	dtors.push(dd);
+	members->push(dd);
+	dd->semantic(sc);
+    }
+
+    switch (postblits.dim)
+    {
+	case 0:
+	    return NULL;
+
+	case 1:
+	    return (FuncDeclaration *)postblits.data[0];
+
+	default:
+	    e = NULL;
+	    for (size_t i = 0; i < postblits.dim; i++)
+	    {	FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i];
+		Expression *ex = new ThisExp(0);
+		ex = new DotVarExp(0, ex, fd, 0);
+		ex = new CallExp(0, ex);
+		e = Expression::combine(e, ex);
+	    }
+	    PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit"));
+	    dd->fbody = new ExpStatement(0, e);
+	    members->push(dd);
+	    dd->semantic(sc);
+	    return dd;
+    }
+}
+
+#endif
+
+/*****************************************
+ * Create inclusive destructor for struct/class by aggregating
+ * all the destructors in dtors[] with the destructors for
+ * all the members.
+ * Note the close similarity with StructDeclaration::buildPostBlit(),
+ * and the ordering changes (runs backward instead of forwards).
+ */
+
+FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
+{
+    //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
+    Expression *e = NULL;
+
+#if DMDV2
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v && v->storage_class & STCfield);
+	Type *tv = v->type->toBasetype();
+	size_t dim = 1;
+	while (tv->ty == Tsarray)
+	{   TypeSArray *ta = (TypeSArray *)tv;
+	    dim *= ((TypeSArray *)tv)->dim->toInteger();
+	    tv = tv->nextOf()->toBasetype();
+	}
+	if (tv->ty == Tstruct)
+	{   TypeStruct *ts = (TypeStruct *)tv;
+	    StructDeclaration *sd = ts->sym;
+	    if (sd->dtor)
+	    {	Expression *ex;
+
+		// this.v
+		ex = new ThisExp(0);
+		ex = new DotVarExp(0, ex, v, 0);
+
+		if (dim == 1)
+		{   // this.v.dtor()
+		    ex = new DotVarExp(0, ex, sd->dtor, 0);
+		    ex = new CallExp(0, ex);
+		}
+		else
+		{
+		    // Typeinfo.destroy(cast(void*)&this.v);
+		    Expression *ea = new AddrExp(0, ex);
+		    ea = new CastExp(0, ea, Type::tvoid->pointerTo());
+
+		    Expression *et = v->type->getTypeInfo(sc);
+		    et = new DotIdExp(0, et, Id::destroy);
+
+		    ex = new CallExp(0, et, ea);
+		}
+		e = Expression::combine(ex, e);	// combine in reverse order
+	    }
+	}
+    }
+
+    /* Build our own "destructor" which executes e
+     */
+    if (e)
+    {	//printf("Building __fieldDtor()\n");
+	DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor"));
+	dd->fbody = new ExpStatement(0, e);
+	dtors.shift(dd);
+	members->push(dd);
+	dd->semantic(sc);
+    }
+#endif
+
+    switch (dtors.dim)
+    {
+	case 0:
+	    return NULL;
+
+	case 1:
+	    return (FuncDeclaration *)dtors.data[0];
+
+	default:
+	    e = NULL;
+	    for (size_t i = 0; i < dtors.dim; i++)
+	    {	FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i];
+		Expression *ex = new ThisExp(0);
+		ex = new DotVarExp(0, ex, fd, 0);
+		ex = new CallExp(0, ex);
+		e = Expression::combine(ex, e);
+	    }
+	    DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor"));
+	    dd->fbody = new ExpStatement(0, e);
+	    members->push(dd);
+	    dd->semantic(sc);
+	    return dd;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/complex_t.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,74 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright and Burton Radons
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_COMPLEX_T_H
+#define DMD_COMPLEX_T_H
+
+/* Roll our own complex type for compilers that don't support complex
+ */
+
+struct complex_t
+{
+    long double re;
+    long double im;    
+
+    complex_t() { this->re = 0; this->im = 0; }
+    complex_t(long double re) { this->re = re; this->im = 0; }
+    complex_t(long double re, long double im) { this->re = re; this->im = im; }
+
+    complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
+    complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
+    complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
+    complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
+    
+    complex_t operator / (complex_t y)
+    {
+	long double abs_y_re = y.re < 0 ? -y.re : y.re;
+	long double abs_y_im = y.im < 0 ? -y.im : y.im;
+	long double r, den;
+
+	if (abs_y_re < abs_y_im)
+	{
+	    r = y.re / y.im;
+	    den = y.im + r * y.re;
+	    return complex_t((re * r + im) / den,
+			     (im * r - re) / den);
+	}
+	else
+	{
+	    r = y.im / y.re;
+	    den = y.re + r * y.im;
+	    return complex_t((re + r * im) / den,
+			     (im - r * re) / den);
+	}
+    }
+
+    operator bool () { return re || im; }
+
+    int operator == (complex_t y) { return re == y.re && im == y.im; }
+    int operator != (complex_t y) { return re != y.re || im != y.im; }
+};
+
+inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
+
+
+inline long double creall(complex_t x)
+{
+    return x.re;
+}
+
+inline long double cimagl(complex_t x)
+{
+    return x.im;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/cond.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,391 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "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++)
+	{
+	    const char *id = (const 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(const char *ident)
+{
+    if (!global.params.debugids)
+	global.params.debugids = new Array();
+    global.params.debugids->push((void *)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, const 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(const char *ident)
+{
+    checkPredefined(0, ident);
+    addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(const char *ident)
+{
+    if (!global.params.versionids)
+	global.params.versionids = new Array();
+    global.params.versionids->push((void *)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(')');
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/cond.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,106 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DEBCOND_H
+#define DMD_DEBCOND_H
+
+struct Expression;
+struct Identifier;
+struct OutBuffer;
+struct Module;
+struct Scope;
+struct ScopeDsymbol;
+#ifdef _DH
+#include "lexer.h" // dmdhg
+#endif
+enum TOK;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+int findCondition(Array *ids, Identifier *ident);
+
+struct Condition
+{
+    Loc loc;
+    int inc;		// 0: not computed yet
+			// 1: include
+			// 2: do not include
+
+    Condition(Loc loc);
+
+    virtual Condition *syntaxCopy() = 0;
+    virtual int include(Scope *sc, ScopeDsymbol *s) = 0;
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
+};
+
+struct DVCondition : Condition
+{
+    unsigned level;
+    Identifier *ident;
+    Module *mod;
+
+    DVCondition(Module *mod, unsigned level, Identifier *ident);
+
+    Condition *syntaxCopy();
+};
+
+struct DebugCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void addGlobalIdent(const char *ident);
+    static void addPredefinedGlobalIdent(const char *ident);
+
+    DebugCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct VersionCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void checkPredefined(Loc loc, const char *ident);
+    static void addGlobalIdent(const char *ident);
+    static void addPredefinedGlobalIdent(const char *ident);
+
+    VersionCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfCondition : Condition
+{
+    Expression *exp;
+
+    StaticIfCondition(Loc loc, Expression *exp);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct IftypeCondition : Condition
+{
+    /* iftype (targ id tok tspec)
+     */
+    Type *targ;
+    Identifier *id;	// can be NULL
+    enum TOK tok;	// ':' or '=='
+    Type *tspec;	// can be NULL
+
+    IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/constfold.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,1606 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+#define LOG 0
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+	e = e->copy();
+	e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int Expression::isConst()
+{
+    //printf("Expression::isConst(): %s\n", toChars());
+    return 0;
+}
+
+int IntegerExp::isConst()
+{
+    return 1;
+}
+
+int RealExp::isConst()
+{
+    return 1;
+}
+
+int ComplexExp::isConst()
+{
+    return 1;
+}
+
+int SymOffExp::isConst()
+{
+    return 2;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+Expression *Neg(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+	e = new RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+	e = new RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+	e = new ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+	e = new IntegerExp(loc, -e1->toInteger(), type);
+    return e;
+}
+
+Expression *Com(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, ~e1->toInteger(), type);
+    return e;
+}
+
+Expression *Not(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(0), type);
+    return e;
+}
+
+Expression *Bool(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(1), type);
+    return e;
+}
+
+Expression *Add(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 + r2);	break;
+	    case 0+1:	v = r1 + i2 * I;		break;
+	    case 0+2:	v = r1 + c2;			break;
+	    case 3+0:	v = i1 * I + r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
+	    case 3+2:	v = i1 * I + c2;		break;
+	    case 6+0:	v = c1 + r2;			break;
+	    case 6+1:	v = c1 + i2 * I;		break;
+	    case 6+2:	v = c1 + c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, i2);		break;
+	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
+	    case 3+0:	v = complex_t(r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 + i2);	break;
+	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
+	    case 6+2:	v = c1 + c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+	e->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e2;
+	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+	e->type = type;
+    }
+    else
+	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return e;
+}
+
+
+Expression *Min(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 - r2);	break;
+	    case 0+1:	v = r1 - i2 * I;		break;
+	    case 0+2:	v = r1 - c2;			break;
+	    case 3+0:	v = i1 * I - r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
+	    case 3+2:	v = i1 * I - c2;		break;
+	    case 6+0:	v = c1 - r2;			break;
+	    case 6+1:	v = c1 - i2 * I;		break;
+	    case 6+2:	v = c1 - c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, -i2);		break;
+	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
+	    case 3+0:	v = complex_t(-r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 - i2);	break;
+	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
+	    case 6+2:	v = c1 - c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+	e->type = type;
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Mul(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	if (e1->type->isreal())
+	{
+#if __DMC__
+	    c = e1->toReal() * e2->toComplex();
+#else
+	    r = e1->toReal();
+	    c = e2->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e1->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toImaginary() * I * e2->toComplex();
+#else
+	    r = e1->toImaginary();
+	    c = e2->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else if (e2->type->isreal())
+	{
+#if __DMC__
+	    c = e2->toReal() * e1->toComplex();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toComplex() * e2->toImaginary() * I;
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else
+	    c = e1->toComplex() * e2->toComplex();
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Div(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	//e1->type->print();
+	//e2->type->print();
+	if (e2->type->isreal())
+	{
+	    if (e1->type->isreal())
+	    {
+		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
+		return e;
+	    }
+#if __DMC__
+	    //r = e2->toReal();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / e2->toReal();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(creall(c) / r, cimagl(c) / r);
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    //r = e2->toImaginary();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / (e2->toImaginary() * I);
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(cimagl(c) / r, -creall(c) / r);
+#endif
+	}
+	else
+	{
+	    c = e1->toComplex() / e2->toComplex();
+	}
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(loc, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) / ((d_uns64) n2);
+	else
+	    n = n1 / n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Mod(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+	complex_t c;
+
+	if (e2->type->isreal())
+	{   real_t r2 = e2->toReal();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
+	// freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?!
+	// arm also doesn't like fmodl
+	    c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2));
+#else
+	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{   real_t i2 = e2->toImaginary();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
+        // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?!
+	// arm also doesn't like fmodl
+	    c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2));
+#else
+	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+#endif
+	}
+	else
+	    assert(0);
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(loc, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) % ((d_uns64) n2);
+	else
+	    n = n1 % n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Shl(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return e;
+}
+
+Expression *Shr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+		value = (d_int8)(value) >> count;
+		break;
+
+	case Tuns8:
+		value = (d_uns8)(value) >> count;
+		break;
+
+	case Tint16:
+		value = (d_int16)(value) >> count;
+		break;
+
+	case Tuns16:
+		value = (d_uns16)(value) >> count;
+		break;
+
+	case Tint32:
+		value = (d_int32)(value) >> count;
+		break;
+
+	case Tuns32:
+		value = (d_uns32)(value) >> count;
+		break;
+
+	case Tint64:
+		value = (d_int64)(value) >> count;
+		break;
+
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *Ushr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+	case Tuns8:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFF) >> count;
+		break;
+
+	case Tint16:
+	case Tuns16:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFFFF) >> count;
+		break;
+
+	case Tint32:
+	case Tuns32:
+		value = (value & 0xFFFFFFFF) >> count;
+		break;
+
+	case Tint64:
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *And(Type *type, Expression *e1, Expression *e2)
+{
+    Expression *e;
+    e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type);
+    return e;
+}
+
+Expression *Or(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type);
+    return e;
+}
+
+Expression *Xor(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ */
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKnull)
+    {
+	if (e2->op == TOKnull)
+	    cmp = 1;
+	else if (e2->op == TOKstring)
+	{   StringExp *es2 = (StringExp *)e2;
+	    cmp = (0 == es2->len);
+	}
+	else if (e2->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	    cmp = !es2->elements || (0 == es2->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e2->op == TOKnull)
+    {
+	if (e1->op == TOKstring)
+	{   StringExp *es1 = (StringExp *)e1;
+	    cmp = (0 == es1->len);
+	}
+	else if (e1->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	    cmp = !es1->elements || (0 == es1->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+
+	if (es1->sz != es2->sz)
+	{
+	    assert(global.errors);
+	    return EXP_CANT_INTERPRET;
+	}
+	if (es1->len == es2->len &&
+	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+	    cmp = 1;
+	else
+	    cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {	// Swap operands and use common code
+	Expression *e = e1;
+	e1 = e2;
+	e2 = e;
+	goto Lsa;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
+    {
+     Lsa:
+	StringExp *es1 = (StringExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	size_t dim1 = es1->len;
+	size_t dim2 = es2->elements ? es2->elements->dim : 0;
+	if (dim1 != dim2)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < dim1; i++)
+	    {
+		uinteger_t c = es1->charAt(i);
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+		if (ee2->isConst() != 1)
+		    return EXP_CANT_INTERPRET;
+		cmp = (c == ee2->toInteger());
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
+	StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+	if (es1->sd != es2->sd)
+	    cmp = 0;
+	else if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    cmp = 1;
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		if (ee1 == ee2)
+		    continue;
+		if (!ee1 || !ee2)
+		{   cmp = 0;
+		    break;
+		}
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+#if 0 // Should handle this
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+    }
+#endif
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	cmp = (r1 == r2);
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+	{
+	    cmp = 0;
+	}
+	else
+	{
+	    cmp = (r1 == r2);
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral())
+    {
+	cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+	return EXP_CANT_INTERPRET;
+    if (op == TOKnotequal)
+	cmp ^= 1;
+    e = new IntegerExp(loc, cmp, type);
+    return e;
+}
+
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKnull && e2->op == TOKnull)
+    {
+	cmp = 1;
+    }
+    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+	SymOffExp *es1 = (SymOffExp *)e1;
+	SymOffExp *es2 = (SymOffExp *)e2;
+
+	cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->isConst() == 1 && e2->isConst() == 1)
+	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+		type, e1, e2);
+    else
+	assert(0);
+    if (op == TOKnotidentity)
+	cmp ^= 1;
+    return new IntegerExp(loc, cmp, type);
+}
+
+
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    integer_t n;
+    real_t r1;
+    real_t r2;
+
+    //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	size_t sz = es1->sz;
+	assert(sz == es2->sz);
+
+	size_t len = es1->len;
+	if (es2->len < len)
+	    len = es2->len;
+
+	int cmp = memcmp(es1->string, es2->string, sz * len);
+	if (cmp == 0)
+	    cmp = es1->len - es2->len;
+
+	switch (op)
+	{
+	    case TOKlt:	n = cmp <  0;	break;
+	    case TOKle:	n = cmp <= 0;	break;
+	    case TOKgt:	n = cmp >  0;	break;
+	    case TOKge:	n = cmp >= 0;	break;
+
+	    case TOKleg:   n = 1;		break;
+	    case TOKlg:	   n = cmp != 0;	break;
+	    case TOKunord: n = 0;		break;
+	    case TOKue:	   n = cmp == 0;	break;
+	    case TOKug:	   n = cmp >  0;	break;
+	    case TOKuge:   n = cmp >= 0;	break;
+	    case TOKul:	   n = cmp <  0;	break;
+	    case TOKule:   n = cmp <= 0;	break;
+
+	    default:
+		assert(0);
+	}
+    }
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	// DMC is the only compiler I know of that handles NAN arguments
+	// correctly in comparisons.
+	switch (op)
+	{
+	    case TOKlt:	   n = r1 <  r2;	break;
+	    case TOKle:	   n = r1 <= r2;	break;
+	    case TOKgt:	   n = r1 >  r2;	break;
+	    case TOKge:	   n = r1 >= r2;	break;
+
+	    case TOKleg:   n = r1 <>=  r2;	break;
+	    case TOKlg:	   n = r1 <>   r2;	break;
+	    case TOKunord: n = r1 !<>= r2;	break;
+	    case TOKue:	   n = r1 !<>  r2;	break;
+	    case TOKug:	   n = r1 !<=  r2;	break;
+	    case TOKuge:   n = r1 !<   r2;	break;
+	    case TOKul:	   n = r1 !>=  r2;	break;
+	    case TOKule:   n = r1 !>   r2;	break;
+
+	    default:
+		assert(0);
+	}
+#else
+	// Don't rely on compiler, handle NAN arguments separately
+#if IN_GCC
+	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+#endif
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = 0;	break;
+		case TOKle:	n = 0;	break;
+		case TOKgt:	n = 0;	break;
+		case TOKge:	n = 0;	break;
+
+		case TOKleg:	n = 0;	break;
+		case TOKlg:	n = 0;	break;
+		case TOKunord:	n = 1;	break;
+		case TOKue:	n = 1;	break;
+		case TOKug:	n = 1;	break;
+		case TOKuge:	n = 1;	break;
+		case TOKul:	n = 1;	break;
+		case TOKule:	n = 1;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = r1 <  r2;	break;
+		case TOKle:	n = r1 <= r2;	break;
+		case TOKgt:	n = r1 >  r2;	break;
+		case TOKge:	n = r1 >= r2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = r1 != r2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = r1 == r2;	break;
+		case TOKug:	n = r1 >  r2;	break;
+		case TOKuge:	n = r1 >= r2;	break;
+		case TOKul:	n = r1 <  r2;	break;
+		case TOKule:	n = r1 <= r2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+
+		case TOKleg:	n = 1;					break;
+		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
+		case TOKunord:	n = 0;					break;
+		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
+		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = n1 <  n2;	break;
+		case TOKle:	n = n1 <= n2;	break;
+		case TOKgt:	n = n1 >  n2;	break;
+		case TOKge:	n = n1 >= n2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = n1 != n2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = n1 == n2;	break;
+		case TOKug:	n = n1 >  n2;	break;
+		case TOKuge:	n = n1 >= n2;	break;
+		case TOKul:	n = n1 <  n2;	break;
+		case TOKule:	n = n1 <= n2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    e = new IntegerExp(loc, n, type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ *  to:	type to cast to
+ *  type: type to paint the result
+ */
+
+Expression *Cast(Type *type, Type *to, Expression *e1)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("\te1->type = %s\n", e1->type->toChars());
+    if (e1->type->equals(type) && type->equals(to))
+	return e1;
+    if (e1->type->implicitConvTo(to) >= MATCHconst ||
+	to->implicitConvTo(e1->type) >= MATCHconst)
+	return expType(to, e1);
+
+    Type *tb = to->toBasetype();
+    Type *typeb = type->toBasetype();
+
+    if (e1->op == TOKstring)
+    {
+	if (tb->ty == Tarray && typeb->ty == Tarray &&
+	    tb->nextOf()->size() == typeb->nextOf()->size())
+	{
+	    return expType(to, e1);
+	}
+    }
+
+    if (e1->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+
+    if (tb->ty == Tbool)
+	e = new IntegerExp(loc, e1->toInteger() != 0, type);
+    else if (type->isintegral())
+    {
+	if (e1->type->isfloating())
+	{   integer_t result;
+	    real_t r = e1->toReal();
+
+	    switch (typeb->ty)
+	    {
+		case Tint8:	result = (d_int8)r;	break;
+		case Tchar:
+		case Tuns8:	result = (d_uns8)r;	break;
+		case Tint16:	result = (d_int16)r;	break;
+		case Twchar:
+		case Tuns16:	result = (d_uns16)r;	break;
+		case Tint32:	result = (d_int32)r;	break;
+		case Tdchar:
+		case Tuns32:	result = (d_uns32)r;	break;
+		case Tint64:	result = (d_int64)r;	break;
+		case Tuns64:	result = (d_uns64)r;	break;
+		default:
+		    assert(0);
+	    }
+
+	    e = new IntegerExp(loc, result, type);
+	}
+	else if (type->isunsigned())
+	    e = new IntegerExp(loc, e1->toUInteger(), type);
+	else
+	    e = new IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {   real_t value = e1->toReal();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {   real_t value = e1->toImaginary();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {   complex_t value = e1->toComplex();
+
+	e = new ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+	e = new IntegerExp(loc, e1->toInteger(), type);
+    else if (tb->ty == Tvoid)
+	e = EXP_CANT_INTERPRET;
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {	// Struct = 0;
+	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+	assert(sd);
+	Expressions *elements = new Expressions;
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    Expression *exp = new IntegerExp(0);
+	    exp = Cast(v->type, v->type, exp);
+	    if (exp == EXP_CANT_INTERPRET)
+		return exp;
+	    elements->push(exp);
+	}
+	e = new StructLiteralExp(loc, sd, elements);
+	e->type = type;
+    }
+    else
+    {
+	error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
+	e = new IntegerExp(loc, 0, Type::tint32);
+    }
+    return e;
+}
+
+
+Expression *ArrayLength(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+
+	e = new IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	size_t dim;
+
+	dim = ale->elements ? ale->elements->dim : 0;
+	e = new IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+	size_t dim = ale->keys->dim;
+
+	e = new IntegerExp(loc, dim, type);
+    }
+    else
+	e = EXP_CANT_INTERPRET;
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Index(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t i = e2->toInteger();
+
+	if (i >= es1->len)
+        e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len);
+	else
+	{   unsigned value = es1->charAt(i);
+	    e = new IntegerExp(loc, value, type);
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+	uinteger_t length = tsa->dim->toInteger();
+	uinteger_t i = e2->toInteger();
+
+	if (i >= length)
+	{
+        e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
+	}
+	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    e = (Expression *)ale->elements->data[i];
+	    e->type = type;
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+	uinteger_t i = e2->toInteger();
+
+	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    if (i >= ale->elements->dim)
+	    {
+            e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+	    }
+	    else
+	    {	e = (Expression *)ale->elements->data[i];
+		e->type = type;
+	    }
+	}
+    }
+    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+    {
+	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+	/* Search the keys backwards, in case there are duplicate keys
+	 */
+	for (size_t i = ae->keys->dim; i;)
+	{
+	    i--;
+	    Expression *ekey = (Expression *)ae->keys->data[i];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+	    if (ex == EXP_CANT_INTERPRET)
+		return ex;
+	    if (ex->isBool(TRUE))
+	    {	e = (Expression *)ae->values->data[i];
+		e->type = type;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {	printf("\te1 = %s\n", e1->toChars());
+	printf("\tlwr = %s\n", lwr->toChars());
+	printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->len || ilwr > iupr)
+        e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{   integer_t value;
+	    void *s;
+	    size_t len = iupr - ilwr;
+	    int sz = es1->sz;
+	    StringExp *es;
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len, es1->postfix);
+	    es->sz = sz;
+	    es->committed = 1;
+	    es->type = type;
+	    e = es;
+	}
+    }
+    else if (e1->op == TOKarrayliteral &&
+	    lwr->op == TOKint64 && upr->op == TOKint64 &&
+	    !e1->checkSideEffect(2))
+    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->elements->dim || ilwr > iupr)
+        e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{
+	    Expressions *elements = new Expressions();
+	    elements->setDim(iupr - ilwr);
+	    memcpy(elements->data,
+		   es1->elements->data + ilwr,
+		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
+	    e = new ArrayLiteralExp(e1->loc, elements);
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Cat(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+    Type *t;
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    //printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->toChars());
+
+    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
+    {	e = e2;
+	goto L2;
+    }
+    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
+    {	e = e1;
+     L2:
+	Type *tn = e->type->toBasetype();
+	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	{
+	    // Create a StringExp
+	    void *s;
+	    StringExp *es;
+	    size_t len = 1;
+	    int sz = tn->size();
+	    integer_t v = e->toInteger();
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, &v, sz);
+
+	    // Add terminating 0
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len);
+	    es->sz = sz;
+	    es->committed = 1;
+	    e = es;
+	}
+	else
+	{   // Create an ArrayLiteralExp
+	    Expressions *elements = new Expressions();
+	    elements->push(e);
+	    e = new ArrayLiteralExp(e->loc, elements);
+	}
+	e->type = type;
+	return e;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + es2->len;
+	int sz = es1->sz;
+
+	if (sz != es2->sz)
+	{
+	    /* Can happen with:
+	     *   auto s = "foo"d ~ "bar"c;
+	     */
+	    assert(global.errors);
+	    return e;
+	}
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed | es2->committed;
+	if (es1->committed)
+	    t = es1->type;
+	else
+	    t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + 1;
+	int sz = es1->sz;
+	integer_t v = e2->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed;
+	t = es1->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = 1 + es2->len;
+	int sz = es2->sz;
+	integer_t v = e1->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy((unsigned char *)s, &v, sz);
+	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es2->committed;
+	t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+	t1->nextOf()->equals(t2->nextOf()))
+    {
+	// Concatenate the arrays
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->insert(es1->elements->dim, es2->elements);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
+	t1->nextOf()->equals(t2->nextOf()))
+    {
+	e = e1;
+	goto L3;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
+	t1->nextOf()->equals(t2->nextOf()))
+    {
+	e = e2;
+     L3:
+	// Concatenate the array with null
+	ArrayLiteralExp *es = (ArrayLiteralExp *)e;
+
+	es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy());
+	e = es;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
+	e1->type->toBasetype()->nextOf()->equals(e2->type))
+    {
+	ArrayLiteralExp *es1;
+	if (e1->op == TOKarrayliteral)
+	{   es1 = (ArrayLiteralExp *)e1;
+	    es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	    es1->elements->push(e2);
+	}
+	else
+	{
+	    es1 = new ArrayLiteralExp(e1->loc, e2);
+	}
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e2->op == TOKarrayliteral &&
+	e2->type->toBasetype()->nextOf()->equals(e1->type))
+    {
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
+	es2->elements->shift(e1);
+	e = es2;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+	t = e1->type;
+	e = e2;
+	goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {	e = e1;
+	t = e2->type;
+      L1:
+	Type *tb = t->toBasetype();
+	if (tb->ty == Tarray && tb->nextOf()->equals(e->type))
+	{   Expressions *expressions = new Expressions();
+	    expressions->push(e);
+	    e = new ArrayLiteralExp(loc, expressions);
+	    e->type = t;
+	}
+	if (!e->type->equals(type))
+	{   StringExp *se = (StringExp *)e->copy();
+	    e = se->castTo(NULL, type);
+	}
+    }
+    return e;
+}
+
+Expression *Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    if (ade->e1->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+		unsigned offset = ae->e2->toInteger();
+		Expression *e = se->getField(type, offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+    return EXP_CANT_INTERPRET;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/dchar.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,482 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "dchar.h"
+#include "mem.h"
+
+#if M_UNICODE
+
+// Converts a char string to Unicode
+
+dchar *Dchar::dup(char *p)
+{
+    dchar *s;
+    size_t len;
+
+    if (!p)
+	return NULL;
+    len = strlen(p);
+    s = (dchar *)mem.malloc((len + 1) * sizeof(dchar));
+    for (unsigned i = 0; i < len; i++)
+    {
+	s[i] = (dchar)(p[i] & 0xFF);
+    }
+    s[len] = 0;
+    return s;
+}
+
+dchar *Dchar::memchr(dchar *p, int c, int count)
+{
+    int u;
+
+    for (u = 0; u < count; u++)
+    {
+	if (p[u] == c)
+	    return p + u;
+    }
+    return NULL;
+}
+
+#if _WIN32 && __DMC__
+__declspec(naked)
+unsigned Dchar::calcHash(const dchar *str, unsigned len)
+{
+    __asm
+    {
+	mov	ECX,4[ESP]
+	mov	EDX,8[ESP]
+	xor	EAX,EAX
+	test	EDX,EDX
+	je	L92
+
+LC8:	cmp	EDX,1
+	je	L98
+	cmp	EDX,2
+	je	LAE
+
+	add	EAX,[ECX]
+//	imul	EAX,EAX,025h
+	lea	EAX,[EAX][EAX*8]
+	add	ECX,4
+	sub	EDX,2
+	jmp	LC8
+
+L98:	mov	DX,[ECX]
+	and	EDX,0FFFFh
+	add	EAX,EDX
+	ret
+
+LAE:	add	EAX,[ECX]
+L92:	ret
+    }
+}
+#else
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    unsigned hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+#endif
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str | 0x200020;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str | 0x200020;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+
+#elif MCBS
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#elif UTF8
+
+// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
+
+char Dchar::mblen[256] =
+{
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
+};
+
+dchar *Dchar::dec(dchar *pstart, dchar *p)
+{
+    while ((p[-1] & 0xC0) == 0x80)
+	p--;
+    return p;
+}
+
+int Dchar::get(dchar *p)
+{
+    unsigned c;
+    unsigned char *q = (unsigned char *)p;
+
+    c = q[0];
+    switch (mblen[c])
+    {
+	case 2:
+	    c = ((c    - 0xC0) << 6) |
+		 (q[1] - 0x80);
+	    break;
+
+	case 3:
+	    c = ((c    - 0xE0) << 12) |
+		((q[1] - 0x80) <<  6) |
+		 (q[2] - 0x80);
+	    break;
+
+	case 4:
+	    c = ((c    - 0xF0) << 18) |
+		((q[1] - 0x80) << 12) |
+		((q[2] - 0x80) <<  6) |
+		 (q[3] - 0x80);
+	    break;
+
+	case 5:
+	    c = ((c    - 0xF8) << 24) |
+		((q[1] - 0x80) << 18) |
+		((q[2] - 0x80) << 12) |
+		((q[3] - 0x80) <<  6) |
+		 (q[4] - 0x80);
+	    break;
+
+	case 6:
+	    c = ((c    - 0xFC) << 30) |
+		((q[1] - 0x80) << 24) |
+		((q[2] - 0x80) << 18) |
+		((q[3] - 0x80) << 12) |
+		((q[4] - 0x80) <<  6) |
+		 (q[5] - 0x80);
+	    break;
+    }
+    return c;
+}
+
+dchar *Dchar::put(dchar *p, unsigned c)
+{
+    if (c <= 0x7F)
+    {
+	*p++ = c;
+    }
+    else if (c <= 0x7FF)
+    {
+	p[0] = 0xC0 + (c >> 6);
+	p[1] = 0x80 + (c & 0x3F);
+	p += 2;
+    }
+    else if (c <= 0xFFFF)
+    {
+	p[0] = 0xE0 + (c >> 12);
+	p[1] = 0x80 + ((c >> 6) & 0x3F);
+	p[2] = 0x80 + (c & 0x3F);
+	p += 3;
+    }
+    else if (c <= 0x1FFFFF)
+    {
+	p[0] = 0xF0 + (c >> 18);
+	p[1] = 0x80 + ((c >> 12) & 0x3F);
+	p[2] = 0x80 + ((c >> 6) & 0x3F);
+	p[3] = 0x80 + (c & 0x3F);
+	p += 4;
+    }
+    else if (c <= 0x3FFFFFF)
+    {
+	p[0] = 0xF8 + (c >> 24);
+	p[1] = 0x80 + ((c >> 18) & 0x3F);
+	p[2] = 0x80 + ((c >> 12) & 0x3F);
+	p[3] = 0x80 + ((c >> 6) & 0x3F);
+	p[4] = 0x80 + (c & 0x3F);
+	p += 5;
+    }
+    else if (c <= 0x7FFFFFFF)
+    {
+	p[0] = 0xFC + (c >> 30);
+	p[1] = 0x80 + ((c >> 24) & 0x3F);
+	p[2] = 0x80 + ((c >> 18) & 0x3F);
+	p[3] = 0x80 + ((c >> 12) & 0x3F);
+	p[4] = 0x80 + ((c >> 6) & 0x3F);
+	p[5] = 0x80 + (c & 0x3F);
+	p += 6;
+    }
+    else
+	assert(0);		// not a UCS-4 character
+    return p;
+}
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#else // ascii
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str | 0x2020;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += ((*(const uint16_t *)str << 8) +
+			 ((const uint8_t *)str)[2]) | 0x202020;
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str | 0x20202020;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#endif
+
+#if 0
+#include <stdio.h>
+
+void main()
+{
+    // Print out values to hardcode into Dchar::mblen[]
+    int c;
+    int s;
+
+    for (c = 0; c < 256; c++)
+    {
+	s = 1;
+	if (c >= 0xC0 && c <= 0xDF)
+	    s = 2;
+	if (c >= 0xE0 && c <= 0xEF)
+	    s = 3;
+	if (c >= 0xF0 && c <= 0xF7)
+	    s = 4;
+	if (c >= 0xF8 && c <= 0xFB)
+	    s = 5;
+	if (c >= 0xFC && c <= 0xFD)
+	    s = 6;
+
+	printf("%d", s);
+	if ((c & 15) == 15)
+	    printf(",\n");
+	else
+	    printf(",");
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/dchar.h	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,194 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#ifndef DCHAR_H
+#define DCHAR_H
+
+#if __GNUC__ && !_WIN32
+#include "gnuc.h"
+#endif
+
+#if _MSC_VER
+    // Disable useless warnings about unreferenced functions
+    #pragma warning (disable : 4514)
+#endif
+
+//#include "root.h"
+typedef size_t hash_t;
+
+#undef TEXT
+
+// NOTE: All functions accepting pointer arguments must not be NULL
+
+#if M_UNICODE
+
+#include <string.h>
+#include <wchar.h>
+
+typedef wchar_t dchar;
+#define TEXT(x)		L##x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; }
+    static int len(const dchar *p) { return wcslen(p); }
+    static dchar get(dchar *p) { return *p; }
+    static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; }
+    static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2)
+    {
+#if __DMC__
+	if (!*s1 && !*s2)	// wcscmp is broken
+	    return 0;
+#endif
+	return wcscmp(s1, s2);
+#if 0
+	return (*s1 == *s2)
+	    ? wcscmp(s1, s2)
+	    : ((int)*s1 - (int)*s2);
+#endif
+    }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return iswalpha(c); }
+    static int isUpper(dchar c) { return iswupper(c); }
+    static int isLower(dchar c) { return iswlower(c); }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::_wcsdup(p); }	// BUG: out of memory?
+    static dchar *dup(char *p);
+    static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); }
+    static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); }
+    static dchar *memchr(dchar *p, int c, int count);
+    static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#elif MCBS
+
+#include <limits.h>
+#include <mbstring.h>
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	MB_LEN_MAX
+
+#elif UTF8
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	6
+
+struct Dchar
+{
+    static char mblen[256];
+
+    static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; }
+    static dchar *dec(dchar *pstart, dchar *p);
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p);
+    static int getprev(dchar *pstart, dchar *p)
+	{ return *dec(pstart, p) & 0xFF; }
+    static dchar *put(dchar *p, unsigned c);
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; }
+    static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; }
+    static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); }
+};
+
+#else
+
+#include <string.h>
+
+#ifndef GCC_SAFE_DMD
+#include <ctype.h>
+#endif
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { return p - 1; }
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p) { return *p & 0xFF; }
+    static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; }
+    static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+#ifndef GCC_SAFE_DMD
+    static int isAlpha(dchar c) { return isalpha(c); }
+    static int isUpper(dchar c) { return isupper(c); }
+    static int isLower(dchar c) { return islower(c); }
+    static int isLocaleUpper(dchar c) { return isupper(c); }
+    static int isLocaleLower(dchar c) { return islower(c); }
+    static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+#endif
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+#ifdef __GNUC__
+    static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); }
+#else
+    static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); }
+#endif
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/declaration.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,1649 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "mtype.h"
+#include "template.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "hdrgen.h"
+
+/********************************* Declaration ****************************/
+
+Declaration::Declaration(Identifier *id)
+    : Dsymbol(id)
+{
+    type = NULL;
+    originalType = NULL;
+    storage_class = STCundefined;
+    protection = PROTundefined;
+    linkage = LINKdefault;
+}
+
+void Declaration::semantic(Scope *sc)
+{
+}
+
+const char *Declaration::kind()
+{
+    return "declaration";
+}
+
+unsigned Declaration::size(Loc loc)
+{
+    assert(type);
+    return type->size();
+}
+
+int Declaration::isStaticConstructor()
+{
+    return FALSE;
+}
+
+int Declaration::isStaticDestructor()
+{
+    return FALSE;
+}
+
+int Declaration::isDelete()
+{
+    return FALSE;
+}
+
+int Declaration::isDataseg()
+{
+    return FALSE;
+}
+
+int Declaration::isCodeseg()
+{
+    return FALSE;
+}
+
+enum PROT Declaration::prot()
+{
+    return protection;
+}
+
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ */
+
+#if DMDV2
+void Declaration::checkModify(Loc loc, Scope *sc, Type *t)
+{
+    if (sc->incontract && isParameter())
+	error(loc, "cannot modify parameter '%s' in contract", toChars());
+
+    if (isCtorinit())
+    {	// It's only modifiable if inside the right constructor
+	Dsymbol *s = sc->func;
+	while (1)
+	{
+	    FuncDeclaration *fd = NULL;
+	    if (s)
+		fd = s->isFuncDeclaration();
+	    if (fd &&
+		((fd->isCtorDeclaration() && storage_class & STCfield) ||
+		 (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) &&
+		fd->toParent() == toParent()
+	       )
+	    {
+		VarDeclaration *v = isVarDeclaration();
+		assert(v);
+		v->ctorinit = 1;
+		//printf("setting ctorinit\n");
+	    }
+	    else
+	    {
+		if (s)
+		{   s = s->toParent2();
+		    continue;
+		}
+		else
+		{
+		    const char *p = isStatic() ? "static " : "";
+		    error(loc, "can only initialize %sconst %s inside %sconstructor",
+			p, toChars(), p);
+		}
+	    }
+	    break;
+	}
+    }
+    else
+    {
+	VarDeclaration *v = isVarDeclaration();
+	if (v && v->canassign == 0)
+	{
+	    const char *p = NULL;
+	    if (isConst())
+		p = "const";
+	    else if (isInvariant())
+		p = "invariant";
+	    else if (storage_class & STCmanifest)
+		p = "manifest constant";
+	    else if (!t->isAssignable())
+		p = "struct with immutable members";
+	    if (p)
+	    {	error(loc, "cannot modify %s", p);
+		halt();
+	    }
+	}
+    }
+}
+#endif
+
+
+/********************************* TupleDeclaration ****************************/
+
+TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
+    : Declaration(id)
+{
+    this->type = NULL;
+    this->objects = objects;
+    this->isexp = 0;
+    this->tupletype = NULL;
+}
+
+Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);
+    return NULL;
+}
+
+const char *TupleDeclaration::kind()
+{
+    return "tuple";
+}
+
+Type *TupleDeclaration::getType()
+{
+    /* If this tuple represents a type, return that type
+     */
+
+    //printf("TupleDeclaration::getType() %s\n", toChars());
+    if (isexp)
+	return NULL;
+    if (!tupletype)
+    {
+	/* It's only a type tuple if all the Object's are types
+	 */
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Object *o = (Object *)objects->data[i];
+
+	    if (o->dyncast() != DYNCAST_TYPE)
+	    {
+		//printf("\tnot[%d], %p, %d\n", i, o, o->dyncast());
+		return NULL;
+	    }
+	}
+
+	/* We know it's a type tuple, so build the TypeTuple
+	 */
+	Arguments *args = new Arguments();
+	args->setDim(objects->dim);
+	OutBuffer buf;
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Type *t = (Type *)objects->data[i];
+
+	    //printf("type = %s\n", t->toChars());
+#if 0
+	    buf.printf("_%s_%d", ident->toChars(), i);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+	    Argument *arg = new Argument(STCin, t, id, NULL);
+#else
+	    Argument *arg = new Argument(0, t, NULL, NULL);
+#endif
+	    args->data[i] = (void *)arg;
+	}
+
+	tupletype = new TypeTuple(args);
+    }
+
+    return tupletype;
+}
+
+int TupleDeclaration::needThis()
+{
+    //printf("TupleDeclaration::needThis(%s)\n", toChars());
+    for (size_t i = 0; i < objects->dim; i++)
+    {   Object *o = (Object *)objects->data[i];
+	if (o->dyncast() == DYNCAST_EXPRESSION)
+	{   Expression *e = (Expression *)o;
+	    if (e->op == TOKdsymbol)
+	    {	DsymbolExp *ve = (DsymbolExp *)e;
+		Declaration *d = ve->s->isDeclaration();
+		if (d && d->needThis())
+		{
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/********************************* TypedefDeclaration ****************************/
+
+TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init)
+    : Declaration(id)
+{
+    this->type = new TypeTypedef(this);
+    this->basetype = basetype->toBasetype();
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hbasetype = NULL;
+#endif
+    this->sem = 0;
+    this->inuse = 0;
+    this->loc = loc;
+    this->sinit = NULL;
+}
+
+Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s)
+{
+    Type *basetype = this->basetype->syntaxCopy();
+
+    Initializer *init = NULL;
+    if (this->init)
+	init = this->init->syntaxCopy();
+
+    assert(!s);
+    TypedefDeclaration *st;
+    st = new TypedefDeclaration(loc, ident, basetype, init);
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    st->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        st->htype = htype->syntaxCopy();
+    if (!hbasetype)
+    {	if (basetype)
+	{   hbasetype = basetype->syntaxCopy();
+	    st->hbasetype = basetype->syntaxCopy();
+	}
+    }
+    else
+        st->hbasetype = hbasetype->syntaxCopy();
+#endif
+    return st;
+}
+
+void TypedefDeclaration::semantic(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem);
+    if (sem == 0)
+    {	sem = 1;
+	basetype = basetype->semantic(loc, sc);
+	sem = 2;
+	type = type->semantic(loc, sc);
+	if (sc->parent->isFuncDeclaration() && init)
+	    semantic2(sc);
+	storage_class |= sc->stc & STCdeprecated;
+    }
+    else if (sem == 1)
+    {
+	error("circular definition");
+    }
+}
+
+void TypedefDeclaration::semantic2(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem);
+    if (sem == 2)
+    {	sem = 3;
+	if (init)
+	{
+	    init = init->semantic(sc, basetype);
+
+	    ExpInitializer *ie = init->isExpInitializer();
+	    if (ie)
+	    {
+		if (ie->exp->type == basetype)
+		    ie->exp->type = type;
+	    }
+	}
+    }
+}
+
+const char *TypedefDeclaration::kind()
+{
+    return "typedef";
+}
+
+Type *TypedefDeclaration::getType()
+{
+    return type;
+}
+
+void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("typedef ");
+    basetype->toCBuffer(buf, ident, hgs);
+    if (init)
+    {
+	buf->writestring(" = ");
+	init->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* AliasDeclaration ****************************/
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+    //printf("type = '%s'\n", type->toChars());
+    this->loc = loc;
+    this->type = type;
+    this->aliassym = NULL;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(type);
+}
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s);
+    assert(s != this);
+    this->loc = loc;
+    this->type = NULL;
+    this->aliassym = s;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(s);
+}
+
+Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("AliasDeclaration::syntaxCopy()\n");
+    assert(!s);
+    AliasDeclaration *sa;
+    if (type)
+	sa = new AliasDeclaration(loc, ident, type->syntaxCopy());
+    else
+	sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)	    // Don't overwrite original
+    {	if (type)	// Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sa->htype = type->syntaxCopy();
+	}
+    }
+    else			// Make copy of original for new instance
+	sa->htype = htype->syntaxCopy();
+    if (!haliassym)
+    {	if (aliassym)
+	{   haliassym = aliassym->syntaxCopy(s);
+	    sa->haliassym = aliassym->syntaxCopy(s);
+	}
+    }
+    else
+	sa->haliassym = haliassym->syntaxCopy(s);
+#endif
+    return sa;
+}
+
+void AliasDeclaration::semantic(Scope *sc)
+{
+    //printf("AliasDeclaration::semantic() %s\n", toChars());
+    if (aliassym)
+    {
+	if (aliassym->isTemplateInstance())
+	    aliassym->semantic(sc);
+	return;
+    }
+    this->inSemantic = 1;
+
+    if (storage_class & STCconst)
+	error("cannot be const");
+
+    storage_class |= sc->stc & STCdeprecated;
+
+    // Given:
+    //	alias foo.bar.abc def;
+    // it is not knowable from the syntax whether this is an alias
+    // for a type or an alias for a symbol. It is up to the semantic()
+    // pass to distinguish.
+    // If it is a type, then type is set and getType() will return that
+    // type. If it is a symbol, then aliassym is set and type is NULL -
+    // toAlias() will return aliasssym.
+
+    Dsymbol *s;
+    Type *t;
+    Expression *e;
+
+    /* This section is needed because resolve() will:
+     *   const x = 3;
+     *   alias x y;
+     * try to alias y to 3.
+     */
+    s = type->toDsymbol(sc);
+    if (s && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()))
+	goto L2;			// it's a symbolic alias
+
+    //printf("alias type is %s\n", type->toChars());
+    type->resolve(loc, sc, &e, &t, &s);
+    if (s)
+    {
+	goto L2;
+    }
+    else if (e)
+    {
+	// Try to convert Expression to Dsymbol
+	s = getDsymbol(e);
+	if (s)
+	    goto L2;
+
+	error("cannot alias an expression %s", e->toChars());
+	t = e->type;
+    }
+    else if (t)
+	type = t;
+    if (overnext)
+	ScopeDsymbol::multiplyDefined(0, this, overnext);
+    this->inSemantic = 0;
+    return;
+
+  L2:
+    //printf("alias is a symbol %s %s\n", s->kind(), s->toChars());
+    type = NULL;
+    VarDeclaration *v = s->isVarDeclaration();
+    if (v && v->linkage == LINKdefault)
+    {
+	error("forward reference of %s", v->toChars());
+	s = NULL;
+    }
+    else
+    {
+	FuncDeclaration *f = s->toAlias()->isFuncDeclaration();
+	if (f)
+	{
+	    if (overnext)
+	    {
+		FuncAliasDeclaration *fa = new FuncAliasDeclaration(f);
+		if (!fa->overloadInsert(overnext))
+		    ScopeDsymbol::multiplyDefined(0, f, overnext);
+		overnext = NULL;
+		s = fa;
+		s->parent = sc->parent;
+	    }
+	}
+	if (overnext)
+	    ScopeDsymbol::multiplyDefined(0, s, overnext);
+	if (s == this)
+	{
+	    assert(global.errors);
+	    s = NULL;
+	}
+    }
+    aliassym = s;
+    this->inSemantic = 0;
+}
+
+int AliasDeclaration::overloadInsert(Dsymbol *s)
+{
+    /* Don't know yet what the aliased symbol is, so assume it can
+     * be overloaded and check later for correctness.
+     */
+
+    //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars());
+    if (overnext == NULL)
+    {	overnext = s;
+	return TRUE;
+    }
+    else
+    {
+	return overnext->overloadInsert(s);
+    }
+}
+
+const char *AliasDeclaration::kind()
+{
+    return "alias";
+}
+
+Type *AliasDeclaration::getType()
+{
+    return type;
+}
+
+Dsymbol *AliasDeclaration::toAlias()
+{
+    //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : "");
+    assert(this != aliassym);
+    //static int count; if (++count == 10) *(char*)0=0;
+    if (inSemantic)
+    {	error("recursive alias declaration");
+//	return this;
+    }
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+#if 0 && _DH
+    if (hgs->hdrgen)
+    {
+	if (haliassym)
+	{
+	    haliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    htype->toCBuffer(buf, ident, hgs);
+    }
+    else
+#endif
+    {
+	if (aliassym)
+	{
+	    aliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    type->toCBuffer(buf, ident, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* VarDeclaration ****************************/
+
+VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
+    : Declaration(id)
+{
+    //printf("VarDeclaration('%s')\n", id->toChars());
+#ifdef DEBUG
+    if (!type && !init)
+    {	printf("VarDeclaration('%s')\n", id->toChars());
+	//*(char*)0=0;
+    }
+#endif
+    assert(type || init);
+    this->type = type;
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hinit = NULL;
+#endif
+    this->loc = loc;
+    offset = 0;
+    noauto = 0;
+    inuse = 0;
+    ctorinit = 0;
+    aliassym = NULL;
+    onstack = 0;
+    canassign = 0;
+    value = NULL;
+    scope = NULL;
+
+    // LDC
+    anonDecl = NULL;
+}
+
+Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+
+    VarDeclaration *sv;
+    if (s)
+    {	sv = (VarDeclaration *)s;
+    }
+    else
+    {
+	Initializer *init = NULL;
+	if (this->init)
+	{   init = this->init->syntaxCopy();
+	    //init->isExpInitializer()->exp->print();
+	    //init->isExpInitializer()->exp->dump(0);
+	}
+
+	sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init);
+	sv->storage_class = storage_class;
+    }
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sv->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        sv->htype = htype->syntaxCopy();
+    if (!hinit)
+    {	if (init)
+	{   hinit = init->syntaxCopy();
+	    sv->hinit = init->syntaxCopy();
+	}
+    }
+    else
+        sv->hinit = hinit->syntaxCopy();
+#endif
+    return sv;
+}
+
+void VarDeclaration::semantic(Scope *sc)
+{
+#if 0
+    printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
+    printf(" type = %s\n", type ? type->toChars() : "null");
+    printf(" stc = x%x\n", sc->stc);
+    printf(" storage_class = x%x\n", storage_class);
+    printf("linkage = %d\n", sc->linkage);
+    //if (strcmp(toChars(), "mul") == 0) halt();
+#endif
+
+    storage_class |= sc->stc;
+    if (storage_class & STCextern && init)
+	error("extern symbols cannot have initializers");
+
+    /* If auto type inference, do the inference
+     */
+    int inferred = 0;
+    if (!type)
+    {	inuse++;
+	type = init->inferType(sc);
+	inuse--;
+	inferred = 1;
+
+	/* This is a kludge to support the existing syntax for RAII
+	 * declarations.
+	 */
+	storage_class &= ~STCauto;
+	originalType = type;
+    }
+    else
+    {	if (!originalType)
+	    originalType = type;
+	type = type->semantic(loc, sc);
+    }
+    //printf(" semantic type = %s\n", type ? type->toChars() : "null");
+
+    type->checkDeprecated(loc, sc);
+    linkage = sc->linkage;
+    this->parent = sc->parent;
+    //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
+    protection = sc->protection;
+    //printf("sc->stc = %x\n", sc->stc);
+    //printf("storage_class = x%x\n", storage_class);
+
+    Dsymbol *parent = toParent();
+    FuncDeclaration *fd = parent->isFuncDeclaration();
+
+    Type *tb = type->toBasetype();
+    if (tb->ty == Tvoid && !(storage_class & STClazy))
+    {	error("voids have no value");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tfunction)
+    {	error("cannot be declared to be a function");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tstruct)
+    {	TypeStruct *ts = (TypeStruct *)tb;
+
+	if (!ts->sym->members)
+	{
+	    error("no definition of struct %s", ts->toChars());
+	}
+    }
+
+    if (tb->ty == Ttuple)
+    {   /* Instead, declare variables for each of the tuple elements
+	 * and add those.
+	 */
+	TypeTuple *tt = (TypeTuple *)tb;
+	size_t nelems = Argument::dim(tt->arguments);
+	Objects *exps = new Objects();
+	exps->setDim(nelems);
+	Expression *ie = init ? init->toExpression() : NULL;
+
+	for (size_t i = 0; i < nelems; i++)
+	{   Argument *arg = Argument::getNth(tt->arguments, i);
+
+	    OutBuffer buf;
+        buf.printf("_%s_field_%"PRIuSIZE, ident->toChars(), i);
+	    buf.writeByte(0);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+
+	    Expression *einit = ie;
+	    if (ie && ie->op == TOKtuple)
+	    {	einit = (Expression *)((TupleExp *)ie)->exps->data[i];
+	    }
+	    Initializer *ti = init;
+	    if (einit)
+	    {	ti = new ExpInitializer(einit->loc, einit);
+	    }
+
+	    VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
+	    //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
+	    v->semantic(sc);
+
+	    if (sc->scopesym)
+	    {	//printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
+		if (sc->scopesym->members)
+		    sc->scopesym->members->push(v);
+	    }
+
+	    Expression *e = new DsymbolExp(loc, v);
+	    exps->data[i] = e;
+	}
+	TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
+	v2->isexp = 1;
+	aliassym = v2;
+	return;
+    }
+
+Lagain:
+    if (storage_class & STCinvariant)
+    {
+	type = type->invariantOf();
+    }
+    else if (storage_class & (STCconst | STCin))
+    {
+	if (!type->isInvariant())
+	    type = type->constOf();
+    }
+    else if (type->isConst())
+	storage_class |= STCconst;
+    else if (type->isInvariant())
+	storage_class |= STCinvariant;
+
+    if (isSynchronized())
+    {
+	error("variable %s cannot be synchronized", toChars());
+    }
+    else if (isOverride())
+    {
+	error("override cannot be applied to variable");
+    }
+    else if (isAbstract())
+    {
+	error("abstract cannot be applied to variable");
+    }
+    else if (storage_class & STCfinal)
+    {
+	error("final cannot be applied to variable");
+    }
+
+    if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls))
+    {
+    }
+    else
+    {
+	AggregateDeclaration *aad = sc->anonAgg;
+	if (!aad)
+	    aad = parent->isAggregateDeclaration();
+	if (aad)
+	{   assert(!(storage_class & (STCextern | STCstatic | STCtls)));
+
+	    if (storage_class & (STCconst | STCinvariant) && init)
+	    {
+		if (!type->toBasetype()->isTypeBasic())
+		    storage_class |= STCstatic;
+	    }
+	    else
+		aad->addField(sc, this);
+	}
+
+	InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+	if (id)
+	{
+	    error("field not allowed in interface");
+	}
+
+	/* Templates cannot add fields to aggregates
+	 */
+	TemplateInstance *ti = parent->isTemplateInstance();
+	if (ti)
+	{
+	    // Take care of nested templates
+	    while (1)
+	    {
+		TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+		if (!ti2)
+		    break;
+		ti = ti2;
+	    }
+
+	    // If it's a member template
+	    AggregateDeclaration *ad = ti->tempdecl->isMember();
+	    if (ad && storage_class != STCundefined)
+	    {
+		error("cannot use template to add field to aggregate '%s'", ad->toChars());
+	    }
+	}
+    }
+
+    if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref)
+	error("only parameters or foreach declarations can be ref");
+
+    if (type->isauto() && !noauto)