diff dmd2/mtype.c @ 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
children 9a9f403ab399
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/mtype.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,6383 @@
+
+// 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.
+
+#define __USE_ISOC99 1		// so signbit() gets defined
+#include <math.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <float.h>
+
+#ifdef __DMC__
+#include <fp.h>
+#endif
+
+#if _MSC_VER
+#include <malloc.h>
+#include <complex>
+#include <limits>
+#elif __DMC__
+#include <complex.h>
+#elif __MINGW32__
+#include <malloc.h>
+#else
+//#define signbit 56
+#endif
+
+#if __APPLE__
+#include <math.h>
+static double zero = 0;
+#elif __MINGW32__
+#include <math.h>
+static double zero = 0;
+#elif __GNUC__
+#include <math.h>
+#include <bits/nan.h>
+#include <bits/mathdef.h>
+static double zero = 0;
+#endif
+
+#include "mem.h"
+
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+
+FuncDeclaration *hasThis(Scope *sc);
+
+
+#define LOGDOTEXP	0	// log ::dotExp()
+#define LOGDEFAULTINIT	0	// log ::defaultInit()
+
+// Allow implicit conversion of T[] to T*
+#define IMPLICIT_ARRAY_TO_PTR	global.params.useDeprecated
+
+/* These have default values for 32 bit code, they get
+ * adjusted for 64 bit code.
+ */
+
+int PTRSIZE = 4;
+#if IN_LLVM
+int REALSIZE = 8;
+int REALPAD = 0;
+#elif TARGET_LINUX
+int REALSIZE = 12;
+int REALPAD = 2;
+#else
+int REALSIZE = 10;
+int REALPAD = 0;
+#endif
+int Tsize_t = Tuns32;
+int Tptrdiff_t = Tint32;
+
+/***************************** Type *****************************/
+
+ClassDeclaration *Type::typeinfo;
+ClassDeclaration *Type::typeinfoclass;
+ClassDeclaration *Type::typeinfointerface;
+ClassDeclaration *Type::typeinfostruct;
+ClassDeclaration *Type::typeinfotypedef;
+ClassDeclaration *Type::typeinfopointer;
+ClassDeclaration *Type::typeinfoarray;
+ClassDeclaration *Type::typeinfostaticarray;
+ClassDeclaration *Type::typeinfoassociativearray;
+ClassDeclaration *Type::typeinfoenum;
+ClassDeclaration *Type::typeinfofunction;
+ClassDeclaration *Type::typeinfodelegate;
+ClassDeclaration *Type::typeinfotypelist;
+ClassDeclaration *Type::typeinfoconst;
+ClassDeclaration *Type::typeinfoinvariant;
+
+Type *Type::tvoidptr;
+Type *Type::basic[TMAX];
+unsigned char Type::mangleChar[TMAX];
+unsigned char Type::sizeTy[TMAX];
+StringTable Type::stringtable;
+
+
+Type::Type(TY ty)
+{
+    this->ty = ty;
+    this->mod = 0;
+    this->deco = NULL;
+#if DMDV2
+    this->cto = NULL;
+    this->ito = NULL;
+#endif
+    this->pto = NULL;
+    this->rto = NULL;
+    this->arrayof = NULL;
+    this->vtinfo = NULL;
+    this->ctype = NULL;
+}
+
+Type *Type::syntaxCopy()
+{
+    print();
+    fprintf(stdmsg, "ty = %d\n", ty);
+    assert(0);
+    return this;
+}
+
+int Type::equals(Object *o)
+{   Type *t;
+
+    t = (Type *)o;
+    //printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
+    if (this == o ||
+	(t && deco == t->deco) &&		// deco strings are unique
+	 deco != NULL)				// and semantic() has been run
+    {
+	//printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+	return 1;
+    }
+    //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+    return 0;
+}
+
+char Type::needThisPrefix()
+{
+    return 'M';		// name mangling prefix for functions needing 'this'
+}
+
+void Type::init()
+{   int i;
+    int j;
+
+    Lexer::initKeywords();
+
+    for (i = 0; i < TMAX; i++)
+	sizeTy[i] = sizeof(TypeBasic);
+    sizeTy[Tsarray] = sizeof(TypeSArray);
+    sizeTy[Tarray] = sizeof(TypeDArray);
+    sizeTy[Taarray] = sizeof(TypeAArray);
+    sizeTy[Tpointer] = sizeof(TypePointer);
+    sizeTy[Treference] = sizeof(TypeReference);
+    sizeTy[Tfunction] = sizeof(TypeFunction);
+    sizeTy[Tdelegate] = sizeof(TypeDelegate);
+    sizeTy[Tident] = sizeof(TypeIdentifier);
+    sizeTy[Tinstance] = sizeof(TypeInstance);
+    sizeTy[Ttypeof] = sizeof(TypeTypeof);
+    sizeTy[Tenum] = sizeof(TypeEnum);
+    sizeTy[Ttypedef] = sizeof(TypeTypedef);
+    sizeTy[Tstruct] = sizeof(TypeStruct);
+    sizeTy[Tclass] = sizeof(TypeClass);
+    sizeTy[Ttuple] = sizeof(TypeTuple);
+    sizeTy[Tslice] = sizeof(TypeSlice);
+    sizeTy[Treturn] = sizeof(TypeReturn);
+
+    mangleChar[Tarray] = 'A';
+    mangleChar[Tsarray] = 'G';
+    mangleChar[Taarray] = 'H';
+    mangleChar[Tpointer] = 'P';
+    mangleChar[Treference] = 'R';
+    mangleChar[Tfunction] = 'F';
+    mangleChar[Tident] = 'I';
+    mangleChar[Tclass] = 'C';
+    mangleChar[Tstruct] = 'S';
+    mangleChar[Tenum] = 'E';
+    mangleChar[Ttypedef] = 'T';
+    mangleChar[Tdelegate] = 'D';
+
+    mangleChar[Tnone] = 'n';
+    mangleChar[Tvoid] = 'v';
+    mangleChar[Tint8] = 'g';
+    mangleChar[Tuns8] = 'h';
+    mangleChar[Tint16] = 's';
+    mangleChar[Tuns16] = 't';
+    mangleChar[Tint32] = 'i';
+    mangleChar[Tuns32] = 'k';
+    mangleChar[Tint64] = 'l';
+    mangleChar[Tuns64] = 'm';
+    mangleChar[Tfloat32] = 'f';
+    mangleChar[Tfloat64] = 'd';
+    mangleChar[Tfloat80] = 'e';
+
+    mangleChar[Timaginary32] = 'o';
+    mangleChar[Timaginary64] = 'p';
+    mangleChar[Timaginary80] = 'j';
+    mangleChar[Tcomplex32] = 'q';
+    mangleChar[Tcomplex64] = 'r';
+    mangleChar[Tcomplex80] = 'c';
+
+    mangleChar[Tbool] = 'b';
+    mangleChar[Tascii] = 'a';
+    mangleChar[Twchar] = 'u';
+    mangleChar[Tdchar] = 'w';
+
+    mangleChar[Tbit] = '@';
+    mangleChar[Tinstance] = '@';
+    mangleChar[Terror] = '@';
+    mangleChar[Ttypeof] = '@';
+    mangleChar[Ttuple] = 'B';
+    mangleChar[Tslice] = '@';
+    mangleChar[Treturn] = '@';
+
+    for (i = 0; i < TMAX; i++)
+    {	if (!mangleChar[i])
+	    fprintf(stdmsg, "ty = %d\n", i);
+	assert(mangleChar[i]);
+    }
+
+    // Set basic types
+    static TY basetab[] =
+	{ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
+	  Tfloat32, Tfloat64, Tfloat80,
+	  Timaginary32, Timaginary64, Timaginary80,
+	  Tcomplex32, Tcomplex64, Tcomplex80,
+	  Tbool,
+	  Tascii, Twchar, Tdchar };
+
+    for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++)
+    {	Type *t = new TypeBasic(basetab[i]);
+	t = t->merge();
+	basic[basetab[i]] = t;
+    }
+    basic[Terror] = basic[Tint32];
+
+    tvoidptr = tvoid->pointerTo();
+
+    // set size_t / ptrdiff_t types and pointer size
+    if (global.params.is64bit)
+    {
+	Tsize_t = Tuns64;
+	Tptrdiff_t = Tint64;
+	PTRSIZE = 8;
+    }
+    else
+    {
+	Tsize_t = Tuns32;
+	Tptrdiff_t = Tint32;
+	PTRSIZE = 4;
+    }
+
+    // set real size and padding
+    if (global.params.cpu == ARCHx86)
+    {
+	REALSIZE = 12;
+	REALPAD = 2;
+    }
+    else if (global.params.cpu == ARCHx86_64)
+    {
+	REALSIZE = 16;
+	REALPAD = 6;
+    }
+    else
+    {
+	REALSIZE = 8;
+	REALPAD = 0;
+    }
+}
+
+d_uns64 Type::size()
+{
+    return size(0);
+}
+
+d_uns64 Type::size(Loc loc)
+{
+    error(loc, "no size for type %s", toChars());
+    return 1;
+}
+
+unsigned Type::alignsize()
+{
+    return size(0);
+}
+
+Type *Type::semantic(Loc loc, Scope *sc)
+{
+    return merge();
+}
+
+/*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ *	MATCHequal	'this' == 'to'
+ *	MATCHconst	'to' is const
+ *	MATCHnomatch	conversion to mutable or invariant
+ */
+
+MATCH Type::constConv(Type *to)
+{
+    if (equals(to))
+	return MATCHexact;
+    if (ty == to->ty && to->mod == MODconst)
+	return MATCHconst;
+    return MATCHnomatch;
+}
+
+Type *Type::constOf()
+{
+    //printf("Type::constOf() %p %s\n", this, toChars());
+    if (isConst())
+	return this;
+    if (cto)
+	return cto;
+    Type *t = makeConst();
+    t = t->merge();
+    cto = t;
+    if (ito)
+	ito->cto = t;
+    //if (t->nextOf()) assert(t->nextOf()->isConst());
+    //printf("-Type::constOf() %p %s\n", t, toChars());
+    return t;
+}
+
+Type *Type::invariantOf()
+{
+    //printf("Type::invariantOf() %p %s\n", this, toChars());
+    if (isInvariant())
+    {
+	return this;
+    }
+    if (ito)
+    {
+	//if (!ito->isInvariant()) printf("\tito is %p %s\n", ito, ito->toChars());
+	assert(ito->isInvariant());
+	return ito;
+    }
+    Type *t = makeInvariant();
+    t = t->merge();
+    ito = t;
+    if (cto)
+	cto->ito = t;
+#if 0 // fails for function types
+    if (t->nextOf() && !t->nextOf()->isInvariant())
+    {
+	assert(0);
+    }
+#endif
+    //printf("\t%p\n", t);
+    return t;
+}
+
+Type *Type::mutableOf()
+{
+    //printf("Type::mutableOf() %p, %s\n", this, toChars());
+    Type *t = this;
+    if (isConst())
+    {	t = cto;
+	assert(!t || t->isMutable());
+    }
+    else if (isInvariant())
+    {	t = ito;
+	assert(!t || t->isMutable());
+    }
+    if (!t)
+    {
+	unsigned sz = sizeTy[ty];
+	t = (Type *)mem.malloc(sz);
+	memcpy(t, this, sz);
+	t->mod = 0;
+	t->deco = NULL;
+	t->arrayof = NULL;
+	t->pto = NULL;
+	t->rto = NULL;
+	t->cto = NULL;
+	t->ito = NULL;
+	t->vtinfo = NULL;
+	if (ty == Tsarray)
+	{   TypeSArray *ta = (TypeSArray *)t;
+	    //ta->next = ta->next->mutableOf();
+	}
+	t = t->merge();
+	if (isConst())
+	{   cto = t;
+	    t->cto = this;
+	    if (ito)
+		ito->cto = this;
+	}
+	else if (isInvariant())
+	{   ito = t;
+	    t->ito = this;
+	    if (cto)
+		cto->ito = this;
+	}
+    }
+    return t;
+}
+
+Type *Type::makeConst()
+{
+    //printf("Type::makeConst() %p, %s\n", this, toChars());
+    if (cto)
+	return cto;
+    unsigned sz = sizeTy[ty];
+    Type *t = (Type *)mem.malloc(sz);
+    memcpy(t, this, sz);
+    t->mod = MODconst;
+    t->deco = NULL;
+    t->arrayof = NULL;
+    t->pto = NULL;
+    t->rto = NULL;
+    t->cto = NULL;
+    t->ito = NULL;
+    t->vtinfo = NULL;
+    //printf("-Type::makeConst() %p, %s\n", t, toChars());
+    return t;
+}
+
+Type *Type::makeInvariant()
+{
+    if (ito)
+	return ito;
+    unsigned sz = sizeTy[ty];
+    Type *t = (Type *)mem.malloc(sz);
+    memcpy(t, this, sz);
+    t->mod = MODinvariant;
+    t->deco = NULL;
+    t->arrayof = NULL;
+    t->pto = NULL;
+    t->rto = NULL;
+    t->cto = NULL;
+    t->ito = NULL;
+    t->vtinfo = NULL;
+    return t;
+}
+
+/**************************
+ * Return type with the top level of it being mutable.
+ */
+Type *Type::toHeadMutable()
+{
+    if (!mod)
+	return this;
+    return mutableOf();
+}
+
+Type *Type::pointerTo()
+{
+    if (!pto)
+    {	Type *t;
+
+	t = new TypePointer(this);
+	pto = t->merge();
+    }
+    return pto;
+}
+
+Type *Type::referenceTo()
+{
+    if (!rto)
+    {	Type *t;
+
+	t = new TypeReference(this);
+	rto = t->merge();
+    }
+    return rto;
+}
+
+Type *Type::arrayOf()
+{
+    if (!arrayof)
+    {	Type *t;
+
+	t = new TypeDArray(this);
+	arrayof = t->merge();
+    }
+    return arrayof;
+}
+
+Dsymbol *Type::toDsymbol(Scope *sc)
+{
+    return NULL;
+}
+
+/*******************************
+ * If this is a shell around another type,
+ * get that other type.
+ */
+
+Type *Type::toBasetype()
+{
+    return this;
+}
+
+/********************************
+ * Name mangling.
+ * Input:
+ *	flag	0x100	do not do const/invariant
+ */
+
+void Type::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    if (flag != mod && flag != 0x100)
+    {
+	if (mod & MODshared)
+	    buf->writeByte('O');
+
+	if (mod & MODconst)
+	    buf->writeByte('x');
+	else if (mod & MODinvariant)
+	    buf->writeByte('y');
+
+	// Cannot be both const and invariant
+	assert((mod & (MODconst | MODinvariant)) != (MODconst | MODinvariant));
+    }
+    buf->writeByte(mangleChar[ty]);
+}
+
+/********************************
+ * For pretty-printing a type.
+ */
+
+char *Type::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    buf = new OutBuffer();
+    toCBuffer(buf, NULL, &hgs);
+    return buf->toChars();
+}
+
+void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    toCBuffer2(buf, hgs, 0);
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(toChars());
+}
+
+void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	const char *p;
+
+	if (mod & MODshared)
+	    buf->writestring("shared(");
+	switch (this->mod & (MODconst | MODinvariant))
+	{
+	    case 0:
+		toCBuffer2(buf, hgs, this->mod);
+		break;
+	    case MODconst:
+		p = "const(";
+		goto L1;
+	    case MODinvariant:
+		p = "invariant(";
+	    L1:	buf->writestring(p);
+		toCBuffer2(buf, hgs, this->mod);
+		buf->writeByte(')');
+		break;
+	    default:
+		assert(0);
+	}
+	if (mod & MODshared)
+	    buf->writeByte(')');
+    }
+}
+
+/************************************
+ */
+
+Type *Type::merge()
+{   Type *t;
+
+    //printf("merge(%s)\n", toChars());
+    t = this;
+    assert(t);
+    if (!deco)
+    {
+	OutBuffer buf;
+	StringValue *sv;
+
+	//if (next)
+	    //next = next->merge();
+	toDecoBuffer(&buf);
+	sv = stringtable.update((char *)buf.data, buf.offset);
+	if (sv->ptrvalue)
+	{   t = (Type *) sv->ptrvalue;
+	    assert(t->deco);
+	    //printf("old value, deco = '%s' %p\n", t->deco, t->deco);
+	}
+	else
+	{
+	    sv->ptrvalue = this;
+	    deco = sv->lstring.string;
+	    //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
+	}
+    }
+    return t;
+}
+
+int Type::isintegral()
+{
+    return FALSE;
+}
+
+int Type::isfloating()
+{
+    return FALSE;
+}
+
+int Type::isreal()
+{
+    return FALSE;
+}
+
+int Type::isimaginary()
+{
+    return FALSE;
+}
+
+int Type::iscomplex()
+{
+    return FALSE;
+}
+
+int Type::isscalar()
+{
+    return FALSE;
+}
+
+int Type::isunsigned()
+{
+    return FALSE;
+}
+
+ClassDeclaration *Type::isClassHandle()
+{
+    return NULL;
+}
+
+int Type::isauto()
+{
+    return FALSE;
+}
+
+int Type::isString()
+{
+    return FALSE;
+}
+
+/**************************
+ * Given:
+ *	T a, b;
+ * Can we assign:
+ *	a = b;
+ * ?
+ */
+int Type::isAssignable()
+{
+    return TRUE;
+}
+
+int Type::checkBoolean()
+{
+    return isscalar();
+}
+
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+
+void Type::checkDeprecated(Loc loc, Scope *sc)
+{
+    Dsymbol *s = toDsymbol(sc);
+
+    if (s)
+	s->checkDeprecated(loc, sc);
+}
+
+
+Expression *Type::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("Type::defaultInit() '%s'\n", toChars());
+#endif
+    return NULL;
+}
+
+int Type::isZeroInit()
+{
+    return 0;		// assume not
+}
+
+int Type::isBaseOf(Type *t, int *poffset)
+{
+    return 0;		// assume not
+}
+
+/********************************
+ * Determine if 'this' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ *	0	can't convert
+ *	1	can convert using implicit conversions
+ *	2	this and to are the same type
+ */
+
+MATCH Type::implicitConvTo(Type *to)
+{
+    //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+    if (this == to)
+	return MATCHexact;
+    return MATCHnomatch;
+}
+
+Expression *Type::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+#if LOGDOTEXP
+    printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::__sizeof)
+    {
+	e = new IntegerExp(loc, size(loc), Type::tsize_t);
+    }
+    else if (ident == Id::size)
+    {
+	error(loc, ".size property should be replaced with .sizeof");
+	e = new IntegerExp(loc, size(loc), Type::tsize_t);
+    }
+    else if (ident == Id::alignof)
+    {
+	e = new IntegerExp(loc, alignsize(), Type::tsize_t);
+    }
+    else if (ident == Id::typeinfo)
+    {
+	if (!global.params.useDeprecated)
+	    error(loc, ".typeinfo deprecated, use typeid(type)");
+	e = getTypeInfo(NULL);
+    }
+    else if (ident == Id::init)
+    {
+	if (ty == Tvoid)
+	    error(loc, "void does not have an initializer");
+	e = defaultInit(loc);
+    }
+    else if (ident == Id::mangleof)
+    {
+	assert(deco);
+	e = new StringExp(loc, deco, strlen(deco), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+    }
+    else if (ident == Id::stringof)
+    {	char *s = toChars();
+	e = new StringExp(loc, s, strlen(s), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+    }
+    else
+    {
+	error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+	e = new IntegerExp(loc, 1, Type::tint32);
+    }
+    return e;
+}
+
+Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   VarDeclaration *v = NULL;
+
+#if LOGDOTEXP
+    printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (e->op == TOKdotvar)
+    {
+	DotVarExp *dv = (DotVarExp *)e;
+	v = dv->var->isVarDeclaration();
+    }
+    else if (e->op == TOKvar)
+    {
+	VarExp *ve = (VarExp *)e;
+	v = ve->var->isVarDeclaration();
+    }
+    if (v)
+    {
+	if (ident == Id::offset)
+	{
+	    if (!global.params.useDeprecated)
+		error(e->loc, ".offset deprecated, use .offsetof");
+	    goto Loffset;
+	}
+	else if (ident == Id::offsetof)
+	{
+	  Loffset:
+	    if (v->storage_class & STCfield)
+	    {
+		e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
+		return e;
+	    }
+	}
+	else if (ident == Id::init)
+	{
+#if 0
+	    if (v->init)
+	    {
+		if (v->init->isVoidInitializer())
+		    error(e->loc, "%s.init is void", v->toChars());
+		else
+		{   Loc loc = e->loc;
+		    e = v->init->toExpression();
+		    if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit)
+		    {
+			e = ((AssignExp *)e)->e2;
+
+			/* Take care of case where we used a 0
+			 * to initialize the struct.
+			 */
+			if (e->type == Type::tint32 &&
+			    e->isBool(0) &&
+			    v->type->toBasetype()->ty == Tstruct)
+			{
+			    e = v->type->defaultInit(e->loc);
+			}
+		    }
+		    e = e->optimize(WANTvalue | WANTinterpret);
+//		    if (!e->isConst())
+//			error(loc, ".init cannot be evaluated at compile time");
+		}
+		return e;
+	    }
+#endif
+	    Expression *ex = defaultInit(e->loc);
+	    return ex;
+	}
+    }
+    if (ident == Id::typeinfo)
+    {
+	if (!global.params.useDeprecated)
+	    error(e->loc, ".typeinfo deprecated, use typeid(type)");
+	e = getTypeInfo(sc);
+	return e;
+    }
+    if (ident == Id::stringof)
+    {	char *s = e->toChars();
+	e = new StringExp(e->loc, s, strlen(s), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+	return e;
+    }
+    return getProperty(e->loc, ident);
+}
+
+unsigned Type::memalign(unsigned salign)
+{
+    return salign;
+}
+
+void Type::error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+Identifier *Type::getTypeInfoIdent(int internal)
+{
+    // _init_10TypeInfo_%s
+    OutBuffer buf;
+    Identifier *id;
+    char *name;
+    int len;
+
+    if (internal)
+    {	buf.writeByte(mangleChar[ty]);
+	if (ty == Tarray)
+	    buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]);
+    }
+    else
+	toDecoBuffer(&buf);
+    len = buf.offset;
+    name = (char *)alloca(19 + sizeof(len) * 3 + len + 1);
+    buf.writeByte(0);
+    sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data);
+// LDC
+// it is not clear where the underscore that's stripped here is added back in
+//    if (global.params.isWindows)
+//	name++;			// C mangling will add it back in
+    //printf("name = %s\n", name);
+    id = Lexer::idPool(name);
+    return id;
+}
+
+TypeBasic *Type::isTypeBasic()
+{
+    return NULL;
+}
+
+
+void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    //printf("Type::resolve() %s, %d\n", toChars(), ty);
+    Type *t = semantic(loc, sc);
+    *pt = t;
+    *pe = NULL;
+    *ps = NULL;
+}
+
+/*******************************
+ * If one of the subtypes of this type is a TypeIdentifier,
+ * i.e. it's an unresolved type, return that type.
+ */
+
+Type *Type::reliesOnTident()
+{
+    return NULL;
+}
+
+/********************************
+ * We've mistakenly parsed this as a type.
+ * Redo it as an Expression.
+ * NULL if cannot.
+ */
+
+Expression *Type::toExpression()
+{
+    return NULL;
+}
+
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+
+int Type::hasPointers()
+{
+    return FALSE;
+}
+
+/*************************************
+ * If this is a type of something, return that something.
+ */
+
+Type *Type::nextOf()
+{
+    return NULL;
+}
+
+/* ============================= TypeNext =========================== */
+
+TypeNext::TypeNext(TY ty, Type *next)
+	: Type(ty)
+{
+    this->next = next;
+}
+
+void TypeNext::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    Type::toDecoBuffer(buf, flag);
+    assert(next != this);
+    //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty);
+    next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
+}
+
+void TypeNext::checkDeprecated(Loc loc, Scope *sc)
+{
+    Type::checkDeprecated(loc, sc);
+    next->checkDeprecated(loc, sc);
+}
+
+
+Type *TypeNext::reliesOnTident()
+{
+    return next->reliesOnTident();
+}
+
+Type *TypeNext::nextOf()
+{
+    return next;
+}
+
+Type *TypeNext::makeConst()
+{
+    //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
+    if (cto)
+	return cto;
+    TypeNext *t = (TypeNext *)Type::makeConst();
+    if (ty != Tfunction && ty != Tdelegate && next->deco &&
+        !next->isInvariant())
+	t->next = next->constOf();
+    //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeInvariant()
+{
+    //printf("TypeNext::makeInvariant() %s\n", toChars());
+    if (ito)
+    {	assert(ito->isInvariant());
+	return ito;
+    }
+    TypeNext *t = (TypeNext *)Type::makeInvariant();
+    if (ty != Tfunction && ty != Tdelegate && next->deco)
+    {	t->next = next->invariantOf();
+    }
+    return t;
+}
+
+MATCH TypeNext::constConv(Type *to)
+{   MATCH m = Type::constConv(to);
+
+    if (m == MATCHconst &&
+        next->constConv(((TypeNext *)to)->next) == MATCHnomatch)
+	m = MATCHnomatch;
+    return m;
+}
+
+
+/* ============================= TypeBasic =========================== */
+
+TypeBasic::TypeBasic(TY ty)
+	: Type(ty)
+{   const char *d;
+    unsigned flags;
+
+#define TFLAGSintegral	1
+#define TFLAGSfloating	2
+#define TFLAGSunsigned	4
+#define TFLAGSreal	8
+#define TFLAGSimaginary	0x10
+#define TFLAGScomplex	0x20
+
+    flags = 0;
+    switch (ty)
+    {
+	case Tvoid:	d = Token::toChars(TOKvoid);
+			break;
+
+	case Tint8:	d = Token::toChars(TOKint8);
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns8:	d = Token::toChars(TOKuns8);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tint16:	d = Token::toChars(TOKint16);
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns16:	d = Token::toChars(TOKuns16);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tint32:	d = Token::toChars(TOKint32);
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns32:	d = Token::toChars(TOKuns32);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tfloat32:	d = Token::toChars(TOKfloat32);
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Tint64:	d = Token::toChars(TOKint64);
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns64:	d = Token::toChars(TOKuns64);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tfloat64:	d = Token::toChars(TOKfloat64);
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Tfloat80:	d = Token::toChars(TOKfloat80);
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Timaginary32: d = Token::toChars(TOKimaginary32);
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Timaginary64: d = Token::toChars(TOKimaginary64);
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Timaginary80: d = Token::toChars(TOKimaginary80);
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Tcomplex32: d = Token::toChars(TOKcomplex32);
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+	case Tcomplex64: d = Token::toChars(TOKcomplex64);
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+	case Tcomplex80: d = Token::toChars(TOKcomplex80);
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+	case Tbool:	d = "bool";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tascii:	d = Token::toChars(TOKchar);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Twchar:	d = Token::toChars(TOKwchar);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tdchar:	d = Token::toChars(TOKdchar);
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	default:	assert(0);
+    }
+    this->dstring = d;
+    this->flags = flags;
+    merge();
+}
+
+Type *TypeBasic::syntaxCopy()
+{
+    // No semantic analysis done on basic types, no need to copy
+    return this;
+}
+
+
+char *TypeBasic::toChars()
+{
+    return Type::toChars();
+}
+
+void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    //printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod);
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(dstring);
+}
+
+d_uns64 TypeBasic::size(Loc loc)
+{   unsigned size;
+
+    //printf("TypeBasic::size()\n");
+    switch (ty)
+    {
+	case Tint8:
+	case Tuns8:	size = 1;	break;
+	case Tint16:
+	case Tuns16:	size = 2;	break;
+	case Tint32:
+	case Tuns32:
+	case Tfloat32:
+	case Timaginary32:
+			size = 4;	break;
+	case Tint64:
+	case Tuns64:
+	case Tfloat64:
+	case Timaginary64:
+			size = 8;	break;
+	case Tfloat80:
+	case Timaginary80:
+			size = REALSIZE;	break;
+	case Tcomplex32:
+			size = 8;		break;
+	case Tcomplex64:
+			size = 16;		break;
+	case Tcomplex80:
+			size = REALSIZE * 2;	break;
+
+	case Tvoid:
+	    //size = Type::size();	// error message
+	    size = 1;
+	    break;
+
+	case Tbool:	size = 1;		break;
+	case Tascii:	size = 1;		break;
+	case Twchar:	size = 2;		break;
+	case Tdchar:	size = 4;		break;
+
+	default:
+	    assert(0);
+	    break;
+    }
+    //printf("TypeBasic::size() = %d\n", size);
+    return size;
+}
+
+unsigned TypeBasic::alignsize()
+{   unsigned sz;
+
+    //LDC: it's bad that we always have to check LLVM's align and
+    // dmd's align info match. Can't we somehow get at LLVM's align
+    // here?
+
+    switch (ty)
+    {
+	case Tfloat80:
+	case Timaginary80:
+	case Tcomplex80:
+	    if (global.params.cpu == ARCHx86_64)
+		sz = 16;
+	    else
+		sz = 4;
+	    break;
+
+	case Tint64:
+	case Tuns64:
+	case Tfloat64:
+	case Timaginary64:
+	    if (global.params.cpu == ARCHx86_64)
+		sz = 8;
+	    else
+		sz = 4;
+	    break;
+
+	default:
+	    sz = size(0);
+	    break;
+    }
+    return sz;
+}
+
+
+Expression *TypeBasic::getProperty(Loc loc, Identifier *ident)
+{
+    Expression *e;
+    d_int64 ivalue;
+#ifdef IN_GCC
+    real_t    fvalue;
+#else
+    d_float80 fvalue;
+#endif
+
+    //printf("TypeBasic::getProperty('%s')\n", ident->toChars());
+    if (ident == Id::max)
+    {
+	switch (ty)
+	{
+	    case Tint8:		ivalue = 0x7F;		goto Livalue;
+	    case Tuns8:		ivalue = 0xFF;		goto Livalue;
+	    case Tint16:	ivalue = 0x7FFFUL;	goto Livalue;
+	    case Tuns16:	ivalue = 0xFFFFUL;	goto Livalue;
+	    case Tint32:	ivalue = 0x7FFFFFFFUL;	goto Livalue;
+	    case Tuns32:	ivalue = 0xFFFFFFFFUL;	goto Livalue;
+	    case Tint64:	ivalue = 0x7FFFFFFFFFFFFFFFLL;	goto Livalue;
+	    case Tuns64:	ivalue = 0xFFFFFFFFFFFFFFFFULL;	goto Livalue;
+	    case Tbool:		ivalue = 1;		goto Livalue;
+	    case Tchar:		ivalue = 0xFF;		goto Livalue;
+	    case Twchar:	ivalue = 0xFFFFUL;	goto Livalue;
+	    case Tdchar:	ivalue = 0x10FFFFUL;	goto Livalue;
+
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_MAX;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_MAX;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_MAX;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::min)
+    {
+	switch (ty)
+	{
+	    case Tint8:		ivalue = -128;		goto Livalue;
+	    case Tuns8:		ivalue = 0;		goto Livalue;
+	    case Tint16:	ivalue = -32768;	goto Livalue;
+	    case Tuns16:	ivalue = 0;		goto Livalue;
+	    case Tint32:	ivalue = -2147483647L - 1;	goto Livalue;
+	    case Tuns32:	ivalue = 0;			goto Livalue;
+	    case Tint64:	ivalue = (-9223372036854775807LL-1LL);	goto Livalue;
+	    case Tuns64:	ivalue = 0;		goto Livalue;
+	    case Tbool:		ivalue = 0;		goto Livalue;
+	    case Tchar:		ivalue = 0;		goto Livalue;
+	    case Twchar:	ivalue = 0;		goto Livalue;
+	    case Tdchar:	ivalue = 0;		goto Livalue;
+
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_MIN;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_MIN;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_MIN;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::nan)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+	    case Timaginary32:
+	    case Timaginary64:
+	    case Timaginary80:
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+	    {
+#if IN_GCC
+		// mode doesn't matter, will be converted in RealExp anyway
+		fvalue = real_t::getnan(real_t::LongDouble);
+#elif __GNUC__
+		// gcc nan's have the sign bit set by default, so turn it off
+		// Need the volatile to prevent gcc from doing incorrect
+		// constant folding.
+		volatile d_float80 foo;
+		foo = NAN;
+		if (signbit(foo))	// signbit sometimes, not always, set
+		    foo = -foo;		// turn off sign bit
+		fvalue = foo;
+#elif _MSC_VER
+		unsigned long nan[2]= { 0xFFFFFFFF, 0x7FFFFFFF };
+		fvalue = *(double*)nan;
+#else
+		fvalue = NAN;
+#endif
+		goto Lfvalue;
+	    }
+	}
+    }
+    else if (ident == Id::infinity)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+	    case Timaginary32:
+	    case Timaginary64:
+	    case Timaginary80:
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+#if IN_GCC
+		fvalue = real_t::getinfinity();
+#elif __GNUC__
+		fvalue = 1 / zero;
+#elif _MSC_VER
+		fvalue = std::numeric_limits<long double>::infinity();
+#else
+		fvalue = INFINITY;
+#endif
+		goto Lfvalue;
+	}
+    }
+    else if (ident == Id::dig)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_DIG;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_DIG;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_DIG;	goto Lint;
+	}
+    }
+    else if (ident == Id::epsilon)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_EPSILON;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_EPSILON;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_EPSILON;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::mant_dig)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MANT_DIG;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MANT_DIG;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MANT_DIG; goto Lint;
+	}
+    }
+    else if (ident == Id::max_10_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MAX_10_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MAX_10_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MAX_10_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::max_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MAX_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MAX_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MAX_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::min_10_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MIN_10_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MIN_10_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MIN_10_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::min_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MIN_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MIN_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MIN_EXP;	goto Lint;
+	}
+    }
+
+Ldefault:
+    return Type::getProperty(loc, ident);
+
+Livalue:
+    e = new IntegerExp(loc, ivalue, this);
+    return e;
+
+Lfvalue:
+    if (isreal() || isimaginary())
+	e = new RealExp(loc, fvalue, this);
+    else
+    {
+	complex_t cvalue;
+
+#if __DMC__
+	//((real_t *)&cvalue)[0] = fvalue;
+	//((real_t *)&cvalue)[1] = fvalue;
+	cvalue = fvalue + fvalue * I;
+#else
+	cvalue.re = fvalue;
+	cvalue.im = fvalue;
+#endif
+	//for (int i = 0; i < 20; i++)
+	//    printf("%02x ", ((unsigned char *)&cvalue)[i]);
+	//printf("\n");
+	e = new ComplexExp(loc, cvalue, this);
+    }
+    return e;
+
+Lint:
+    e = new IntegerExp(loc, ivalue, Type::tint32);
+    return e;
+}
+
+Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    Type *t;
+
+    if (ident == Id::re)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:	t = tfloat32;		goto L1;
+	    case Tcomplex64:	t = tfloat64;		goto L1;
+	    case Tcomplex80:	t = tfloat80;		goto L1;
+	    L1:
+		e = e->castTo(sc, t);
+		break;
+
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+		break;
+
+	    case Timaginary32:	t = tfloat32;		goto L2;
+	    case Timaginary64:	t = tfloat64;		goto L2;
+	    case Timaginary80:	t = tfloat80;		goto L2;
+	    L2:
+		e = new RealExp(0, 0.0, t);
+		break;
+
+	    default:
+		return Type::getProperty(e->loc, ident);
+	}
+    }
+    else if (ident == Id::im)
+    {	Type *t2;
+
+	switch (ty)
+	{
+	    case Tcomplex32:	t = timaginary32;	t2 = tfloat32;	goto L3;
+	    case Tcomplex64:	t = timaginary64;	t2 = tfloat64;	goto L3;
+	    case Tcomplex80:	t = timaginary80;	t2 = tfloat80;	goto L3;
+	    L3:
+		e = e->castTo(sc, t);
+		e->type = t2;
+		break;
+
+	    case Timaginary32:	t = tfloat32;	goto L4;
+	    case Timaginary64:	t = tfloat64;	goto L4;
+	    case Timaginary80:	t = tfloat80;	goto L4;
+	    L4:
+		e = e->copy();
+		e->type = t;
+		break;
+
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+		e = new RealExp(0, 0.0, this);
+		break;
+
+	    default:
+		return Type::getProperty(e->loc, ident);
+	}
+    }
+    else
+    {
+	return Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+Expression *TypeBasic::defaultInit(Loc loc)
+{   integer_t value = 0;
+
+#if LOGDEFAULTINIT
+    printf("TypeBasic::defaultInit() '%s'\n", toChars());
+#endif
+    switch (ty)
+    {
+	case Tvoid:
+	    return new IntegerExp(loc, value, Type::tbool);
+
+	case Tchar:
+	    value = 0xFF;
+	    break;
+
+	case Twchar:
+	case Tdchar:
+	    value = 0xFFFF;
+	    break;
+
+	case Timaginary32:
+	case Timaginary64:
+	case Timaginary80:
+	case Tfloat32:
+	case Tfloat64:
+	case Tfloat80:
+	case Tcomplex32:
+	case Tcomplex64:
+	case Tcomplex80:
+	    return getProperty(loc, Id::nan);
+    }
+    return new IntegerExp(loc, value, this);
+}
+
+int TypeBasic::isZeroInit()
+{
+    switch (ty)
+    {
+	case Tchar:
+	case Twchar:
+	case Tdchar:
+	case Timaginary32:
+	case Timaginary64:
+	case Timaginary80:
+	case Tfloat32:
+	case Tfloat64:
+	case Tfloat80:
+	case Tcomplex32:
+	case Tcomplex64:
+	case Tcomplex80:
+	    return 0;		// no
+    }
+    return 1;			// yes
+}
+
+int TypeBasic::isintegral()
+{
+    //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+    return flags & TFLAGSintegral;
+}
+
+int TypeBasic::isfloating()
+{
+    return flags & TFLAGSfloating;
+}
+
+int TypeBasic::isreal()
+{
+    return flags & TFLAGSreal;
+}
+
+int TypeBasic::isimaginary()
+{
+    return flags & TFLAGSimaginary;
+}
+
+int TypeBasic::iscomplex()
+{
+    return flags & TFLAGScomplex;
+}
+
+int TypeBasic::isunsigned()
+{
+    return flags & TFLAGSunsigned;
+}
+
+int TypeBasic::isscalar()
+{
+    return flags & (TFLAGSintegral | TFLAGSfloating);
+}
+
+MATCH TypeBasic::implicitConvTo(Type *to)
+{
+    //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+    if (this == to)
+	return MATCHexact;
+
+    if (ty == to->ty)
+    {
+	return (mod == to->mod) ? MATCHexact : MATCHconst;
+    }
+
+    if (ty == Tvoid || to->ty == Tvoid)
+	return MATCHnomatch;
+    if (1 || global.params.Dversion == 1)
+    {
+	if (to->ty == Tbool)
+	    return MATCHnomatch;
+    }
+    else
+    {
+	if (ty == Tbool || to->ty == Tbool)
+	    return MATCHnomatch;
+    }
+    if (!to->isTypeBasic())
+	return MATCHnomatch;
+
+    TypeBasic *tob = (TypeBasic *)to;
+    if (flags & TFLAGSintegral)
+    {
+	// Disallow implicit conversion of integers to imaginary or complex
+	if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
+	    return MATCHnomatch;
+
+	// If converting to integral
+	if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral)
+	{   d_uns64 sz = size(0);
+	    d_uns64 tosz = tob->size(0);
+
+	    /* Can't convert to smaller size or, if same size, change sign
+	     */
+	    if (sz > tosz)
+		return MATCHnomatch;
+
+	    /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
+		return MATCHnomatch;*/
+	}
+    }
+    else if (flags & TFLAGSfloating)
+    {
+	// Disallow implicit conversion of floating point to integer
+	if (tob->flags & TFLAGSintegral)
+	    return MATCHnomatch;
+
+	assert(tob->flags & TFLAGSfloating);
+
+	// Disallow implicit conversion from complex to non-complex
+	if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
+	    return MATCHnomatch;
+
+	// Disallow implicit conversion of real or imaginary to complex
+	if (flags & (TFLAGSreal | TFLAGSimaginary) &&
+	    tob->flags & TFLAGScomplex)
+	    return MATCHnomatch;
+
+	// Disallow implicit conversion to-from real and imaginary
+	if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
+	    (tob->flags & (TFLAGSreal | TFLAGSimaginary)))
+	    return MATCHnomatch;
+    }
+    return MATCHconvert;
+}
+
+TypeBasic *TypeBasic::isTypeBasic()
+{
+    return (TypeBasic *)this;
+}
+
+/***************************** TypeArray *****************************/
+
+TypeArray::TypeArray(TY ty, Type *next)
+    : TypeNext(ty, next)
+{
+}
+
+Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+    Type *n = this->next->toBasetype();		// uncover any typedef's
+
+#if LOGDOTEXP
+    printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
+    {
+	Expression *ec;
+	Expressions *arguments;
+
+	//LDC: Build arguments.
+	static FuncDeclaration *adReverseChar_fd = NULL;
+	if(!adReverseChar_fd) {
+	    Arguments* args = new Arguments;
+	    Type* arrty = Type::tchar->arrayOf();
+	    args->push(new Argument(STCin, arrty, NULL, NULL));
+	    adReverseChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseChar");
+	}
+	static FuncDeclaration *adReverseWchar_fd = NULL;
+	if(!adReverseWchar_fd) {
+	    Arguments* args = new Arguments;
+	    Type* arrty = Type::twchar->arrayOf();
+	    args->push(new Argument(STCin, arrty, NULL, NULL));
+	    adReverseWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseWchar");
+	}
+
+	if(n->ty == Twchar)
+	    ec = new VarExp(0, adReverseWchar_fd);
+	else
+	    ec = new VarExp(0, adReverseChar_fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar))
+    {
+	Expression *ec;
+	Expressions *arguments;
+
+	//LDC: Build arguments.
+	static FuncDeclaration *adSortChar_fd = NULL;
+	if(!adSortChar_fd) {
+	    Arguments* args = new Arguments;
+	    Type* arrty = Type::tchar->arrayOf();
+	    args->push(new Argument(STCin, arrty, NULL, NULL));
+	    adSortChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortChar");
+	}
+	static FuncDeclaration *adSortWchar_fd = NULL;
+	if(!adSortWchar_fd) {
+	    Arguments* args = new Arguments;
+	    Type* arrty = Type::twchar->arrayOf();
+	    args->push(new Argument(STCin, arrty, NULL, NULL));
+	    adSortWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortWchar");
+	}
+
+	if(n->ty == Twchar)
+	    ec = new VarExp(0, adSortWchar_fd);
+	else
+	    ec = new VarExp(0, adSortChar_fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::reverse || ident == Id::dup || ident == Id::idup)
+    {
+	Expression *ec;
+	Expressions *arguments;
+	int size = next->size(e->loc);
+	int dup;
+
+	assert(size);
+	dup = (ident == Id::dup || ident == Id::idup);
+	//LDC: Build arguments.
+	static FuncDeclaration *adDup_fd = NULL;
+	if(!adDup_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
+	    args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
+	    adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup);
+	}
+	static FuncDeclaration *adReverse_fd = NULL;
+	if(!adReverse_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
+	    adReverse_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adReverse);
+	}
+
+	if(dup)
+	    ec = new VarExp(0, adDup_fd);
+	else
+	    ec = new VarExp(0, adReverse_fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	if (dup)
+	    arguments->push(getTypeInfo(sc));
+
+    // LDC repaint array type to void[]
+    if (n->ty != Tvoid) {
+        e = new CastExp(e->loc, e, e->type);
+        e->type = Type::tvoid->arrayOf();
+    }
+    arguments->push(e);
+
+	if (!dup)
+	    arguments->push(new IntegerExp(0, size, Type::tint32));
+	e = new CallExp(e->loc, ec, arguments);
+	if (ident == Id::idup)
+	{   Type *einv = next->invariantOf();
+	    if (next->implicitConvTo(einv) < MATCHconst)
+		error(e->loc, "cannot implicitly convert element type %s to invariant", next->toChars());
+	    e->type = einv->arrayOf();
+	}
+	else
+	    e->type = next->mutableOf()->arrayOf();
+    }
+    else if (ident == Id::sort)
+    {
+	Expression *ec;
+	Expressions *arguments;
+	bool isBit = (n->ty == Tbit);
+
+	//LDC: Build arguments.
+	static FuncDeclaration *adSort_fd = NULL;
+	if(!adSort_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
+	    adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort");
+	}
+	static FuncDeclaration *adSortBit_fd = NULL;
+	if(!adSortBit_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
+	    adSortBit_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSortBit");
+	}
+
+	if(isBit)
+	    ec = new VarExp(0, adSortBit_fd);
+	else
+	    ec = new VarExp(0, adSort_fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+
+    // LDC repaint array type to void[]
+    if (n->ty != Tvoid) {
+        e = new CastExp(e->loc, e, e->type);
+        e->type = Type::tvoid->arrayOf();
+    }
+    arguments->push(e);
+
+    arguments->push(n->getTypeInfo(sc));   // LDC, we don't support the getInternalTypeInfo
+                                           // optimization arbitrarily, not yet at least...
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+
+
+/***************************** TypeSArray *****************************/
+
+TypeSArray::TypeSArray(Type *t, Expression *dim)
+    : TypeArray(Tsarray, t)
+{
+    //printf("TypeSArray(%s)\n", dim->toChars());
+    this->dim = dim;
+}
+
+Type *TypeSArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Expression *e = dim->syntaxCopy();
+    t = new TypeSArray(t, e);
+    t->mod = mod;
+    return t;
+}
+
+d_uns64 TypeSArray::size(Loc loc)
+{   integer_t sz;
+
+    if (!dim)
+	return Type::size(loc);
+    sz = dim->toInteger();
+
+    {	integer_t n, n2;
+
+	n = next->size();
+	n2 = n * sz;
+	if (n && (n2 / n) != sz)
+	    goto Loverflow;
+	sz = n2;
+    }
+    return sz;
+
+Loverflow:
+    error(loc, "index %lld overflow for static array", sz);
+    return 1;
+}
+
+unsigned TypeSArray::alignsize()
+{
+    return next->alignsize();
+}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
+{
+    if (t->ty == Ttuple)
+    {	ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+
+	exp = exp->semantic(sc);
+
+	sc->pop();
+    }
+    else
+	exp = exp->semantic(sc);
+    return exp;
+}
+
+Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
+{
+    ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    exp = exp->semantic(sc);
+
+    sc->pop();
+    return exp;
+}
+
+void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    //printf("TypeSArray::resolve() %s\n", toChars());
+    next->resolve(loc, sc, pe, pt, ps);
+    //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+    if (*pe)
+    {	// It's really an index expression
+	Expression *e = new IndexExp(loc, *pe, dim);
+	*pe = e;
+    }
+    else if (*ps)
+    {	Dsymbol *s = *ps;
+	TupleDeclaration *td = s->isTupleDeclaration();
+	if (td)
+	{
+	    ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+	    sym->parent = sc->scopesym;
+	    sc = sc->push(sym);
+
+	    dim = dim->semantic(sc);
+	    dim = dim->optimize(WANTvalue | WANTinterpret);
+	    uinteger_t d = dim->toUInteger();
+
+	    sc = sc->pop();
+
+	    if (d >= td->objects->dim)
+	    {	error(loc, "tuple index %llu exceeds %u", d, td->objects->dim);
+		goto Ldefault;
+	    }
+	    Object *o = (Object *)td->objects->data[(size_t)d];
+	    if (o->dyncast() == DYNCAST_DSYMBOL)
+	    {
+		*ps = (Dsymbol *)o;
+		return;
+	    }
+	    if (o->dyncast() == DYNCAST_EXPRESSION)
+	    {
+		*ps = NULL;
+		*pe = (Expression *)o;
+		return;
+	    }
+
+	    /* Create a new TupleDeclaration which
+	     * is a slice [d..d+1] out of the old one.
+	     * Do it this way because TemplateInstance::semanticTiargs()
+	     * can handle unresolved Objects this way.
+	     */
+	    Objects *objects = new Objects;
+	    objects->setDim(1);
+	    objects->data[0] = o;
+
+	    TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+	    *ps = tds;
+	}
+	else
+	    goto Ldefault;
+    }
+    else
+    {
+     Ldefault:
+	Type::resolve(loc, sc, pe, pt, ps);
+    }
+}
+
+Type *TypeSArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSArray::semantic() %s\n", toChars());
+
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+    next->resolve(loc, sc, &e, &t, &s);
+    if (dim && s && s->isTupleDeclaration())
+    {	TupleDeclaration *sd = s->isTupleDeclaration();
+
+	dim = semanticLength(sc, sd, dim);
+	dim = dim->optimize(WANTvalue | WANTinterpret);
+	uinteger_t d = dim->toUInteger();
+
+	if (d >= sd->objects->dim)
+	{   error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
+	    return Type::terror;
+	}
+	Object *o = (Object *)sd->objects->data[(size_t)d];
+	if (o->dyncast() != DYNCAST_TYPE)
+	{   error(loc, "%s is not a type", toChars());
+	    return Type::terror;
+	}
+	t = (Type *)o;
+	return t;
+    }
+
+    next = next->semantic(loc,sc);
+    if (mod == MODconst && !next->isInvariant())
+	next = next->constOf();
+    else if (mod == MODinvariant)
+	next = next->invariantOf();
+
+    Type *tbn = next->toBasetype();
+
+    if (dim)
+    {	integer_t n, n2;
+
+	dim = semanticLength(sc, tbn, dim);
+
+	dim = dim->optimize(WANTvalue | WANTinterpret);
+	if (sc && sc->parameterSpecialization && dim->op == TOKvar &&
+	    ((VarExp *)dim)->var->storage_class & STCtemplateparameter)
+	{
+	    /* It could be a template parameter N which has no value yet:
+	     *   template Foo(T : T[N], size_t N);
+	     */
+	    return this;
+	}
+	integer_t d1 = dim->toInteger();
+	dim = dim->castTo(sc, tsize_t);
+	dim = dim->optimize(WANTvalue);
+	integer_t d2 = dim->toInteger();
+
+	if (d1 != d2)
+	    goto Loverflow;
+
+	if (tbn->isintegral() ||
+		 tbn->isfloating() ||
+		 tbn->ty == Tpointer ||
+		 tbn->ty == Tarray ||
+		 tbn->ty == Tsarray ||
+		 tbn->ty == Taarray ||
+		 tbn->ty == Tclass)
+	{
+	    /* Only do this for types that don't need to have semantic()
+	     * run on them for the size, since they may be forward referenced.
+	     */
+	    n = tbn->size(loc);
+	    n2 = n * d2;
+	    if ((int)n2 < 0)
+		goto Loverflow;
+	    if (n2 >= 0x1000000)	// put a 'reasonable' limit on it
+		goto Loverflow;
+	    if (n && n2 / n != d2)
+	    {
+	      Loverflow:
+		error(loc, "index %lld overflow for static array", d1);
+		dim = new IntegerExp(0, 1, tsize_t);
+	    }
+	}
+    }
+    switch (tbn->ty)
+    {
+	case Ttuple:
+	{   // Index the tuple to get the type
+	    assert(dim);
+	    TypeTuple *tt = (TypeTuple *)tbn;
+	    uinteger_t d = dim->toUInteger();
+
+	    if (d >= tt->arguments->dim)
+	    {	error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
+		return Type::terror;
+	    }
+	    Argument *arg = (Argument *)tt->arguments->data[(size_t)d];
+	    return arg->type;
+	}
+	case Tfunction:
+	case Tnone:
+	    error(loc, "can't have array of %s", tbn->toChars());
+	    tbn = next = tint32;
+	    break;
+    }
+    if (tbn->isauto())
+	error(loc, "cannot have array of auto %s", tbn->toChars());
+    return merge();
+}
+
+void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    Type::toDecoBuffer(buf, flag);
+    if (dim)
+	buf->printf("%llu", dim->toInteger());
+    if (next)
+	/* Note that static arrays are value types, so
+	 * for a parameter, propagate the 0x100 to the next
+	 * level, since for T[4][3], any const should apply to the T,
+	 * not the [4].
+	 */
+	next->toDecoBuffer(buf,  (flag & 0x100) ? flag : mod);
+}
+
+void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+    buf->printf("[%s]", dim->toChars());
+}
+
+Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	e = dim;
+    }
+    else if (ident == Id::ptr)
+    {
+	e = e->castTo(sc, next->pointerTo());
+    }
+    else
+    {
+	e = TypeArray::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeSArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+unsigned TypeSArray::memalign(unsigned salign)
+{
+    return next->memalign(salign);
+}
+
+MATCH TypeSArray::constConv(Type *to)
+{
+    if (to->ty == Tsarray)
+    {
+	TypeSArray *tsa = (TypeSArray *)to;
+	if (!dim->equals(tsa->dim))
+	    return MATCHnomatch;
+    }
+    return TypeNext::constConv(to);
+}
+
+MATCH TypeSArray::implicitConvTo(Type *to)
+{
+    //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+
+    // Allow implicit conversion of static array to pointer or dynamic array
+    if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
+    {
+	TypePointer *tp = (TypePointer *)to;
+
+	if (next->mod != tp->next->mod && tp->next->mod != MODconst)
+	    return MATCHnomatch;
+
+	if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch)
+	{
+	    return MATCHconvert;
+	}
+	return MATCHnomatch;
+    }
+    if (to->ty == Tarray)
+    {	int offset = 0;
+	TypeDArray *ta = (TypeDArray *)to;
+
+	if (next->mod != ta->next->mod && ta->next->mod != MODconst)
+	    return MATCHnomatch;
+
+	if (next->equals(ta->next) ||
+	    next->implicitConvTo(ta->next) >= MATCHconst ||
+	    (ta->next->isBaseOf(next, &offset) && offset == 0) ||
+	    ta->next->ty == Tvoid)
+	    return MATCHconvert;
+	return MATCHnomatch;
+    }
+    if (to->ty == Tsarray)
+    {
+	if (this == to)
+	    return MATCHexact;
+
+	TypeSArray *tsa = (TypeSArray *)to;
+
+	if (dim->equals(tsa->dim))
+	{
+	    /* Since static arrays are value types, allow
+	     * conversions from const elements to non-const
+	     * ones, just like we allow conversion from const int
+	     * to int.
+	     */
+	    MATCH m = next->implicitConvTo(tsa->next);
+	    if (m >= MATCHconst)
+	    {
+		if (mod != to->mod)
+		    m = MATCHconst;
+		return m;
+	    }
+	}
+    }
+    return MATCHnomatch;
+}
+
+Expression *TypeSArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeSArray::defaultInit() '%s'\n", toChars());
+#endif
+    return next->defaultInit(loc);
+}
+
+int TypeSArray::isZeroInit()
+{
+    return next->isZeroInit();
+}
+
+
+Expression *TypeSArray::toExpression()
+{
+    Expression *e = next->toExpression();
+    if (e)
+    {	Expressions *arguments = new Expressions();
+	arguments->push(dim);
+	e = new ArrayExp(dim->loc, e, arguments);
+    }
+    return e;
+}
+
+int TypeSArray::hasPointers()
+{
+    return next->hasPointers();
+}
+
+/***************************** TypeDArray *****************************/
+
+TypeDArray::TypeDArray(Type *t)
+    : TypeArray(Tarray, t)
+{
+    //printf("TypeDArray(t = %p)\n", t);
+}
+
+Type *TypeDArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+    {	t = new TypeDArray(t);
+	t->mod = mod;
+    }
+    return t;
+}
+
+d_uns64 TypeDArray::size(Loc loc)
+{
+    //printf("TypeDArray::size()\n");
+    return PTRSIZE * 2;
+}
+
+unsigned TypeDArray::alignsize()
+{
+    // A DArray consists of two ptr-sized values, so align it on pointer size
+    // boundary
+    return PTRSIZE;
+}
+
+Type *TypeDArray::semantic(Loc loc, Scope *sc)
+{   Type *tn = next;
+
+    tn = next->semantic(loc,sc);
+    Type *tbn = tn->toBasetype();
+    switch (tbn->ty)
+    {
+	case Tfunction:
+	case Tnone:
+	case Ttuple:
+	    error(loc, "can't have array of %s", tbn->toChars());
+	    tn = next = tint32;
+	    break;
+    }
+    if (tn->isauto())
+	error(loc, "cannot have array of auto %s", tn->toChars());
+
+    if (mod == MODconst && !tn->isInvariant())
+	tn = tn->constOf();
+    else if (mod == MODinvariant)
+	tn = tn->invariantOf();
+
+    next = tn;
+    return merge();
+}
+
+void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    Type::toDecoBuffer(buf, flag);
+    if (next)
+	next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
+}
+
+void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+    buf->writestring("[]");
+}
+
+Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	if (e->op == TOKstring)
+	{   StringExp *se = (StringExp *)e;
+
+	    return new IntegerExp(se->loc, se->len, Type::tindex);
+	}
+	e = new ArrayLengthExp(e->loc, e);
+	e->type = Type::tsize_t;
+	return e;
+    }
+    else if (ident == Id::ptr)
+    {
+	e = e->castTo(sc, next->pointerTo());
+	return e;
+    }
+    else
+    {
+	e = TypeArray::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeDArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeDArray::implicitConvTo(Type *to)
+{
+    //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+    if (equals(to))
+	return MATCHexact;
+
+    // Allow implicit conversion of array to pointer
+    if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
+    {
+	TypePointer *tp = (TypePointer *)to;
+
+	/* Allow conversion to void*
+	 */
+	if (tp->next->ty == Tvoid &&
+	    (next->mod == tp->next->mod || tp->next->mod == MODconst))
+	{
+	    return MATCHconvert;
+	}
+
+	return next->constConv(to);
+    }
+
+    if (to->ty == Tarray)
+    {	int offset = 0;
+	TypeDArray *ta = (TypeDArray *)to;
+
+	if (!(next->mod == ta->next->mod || ta->next->mod == MODconst))
+	    return MATCHnomatch;	// not const-compatible
+
+	/* Allow conversion to void[]
+	 */
+	if (next->ty != Tvoid && ta->next->ty == Tvoid)
+	{
+	    return MATCHconvert;
+	}
+
+	MATCH m = next->constConv(ta->next);
+	if (m != MATCHnomatch)
+	{
+	    if (m == MATCHexact && mod != to->mod)
+		m = MATCHconst;
+	    return m;
+	}
+
+	/* Allow conversions of T[][] to const(T)[][]
+	 */
+	if (mod == ta->mod && next->ty == Tarray && ta->next->ty == Tarray)
+	{
+	    m = next->implicitConvTo(ta->next);
+	    if (m == MATCHconst)
+		return m;
+	}
+
+	/* Conversion of array of derived to array of base
+	 */
+	if (ta->next->isBaseOf(next, &offset) && offset == 0)
+	    return MATCHconvert;
+    }
+    return Type::implicitConvTo(to);
+}
+
+Expression *TypeDArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeDArray::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypeDArray::isZeroInit()
+{
+    return 1;
+}
+
+int TypeDArray::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeDArray::hasPointers()
+{
+    return TRUE;
+}
+
+/***************************** TypeAArray *****************************/
+
+TypeAArray::TypeAArray(Type *t, Type *index)
+    : TypeArray(Taarray, t)
+{
+    this->index = index;
+}
+
+Type *TypeAArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Type *ti = index->syntaxCopy();
+    if (t == next && ti == index)
+	t = this;
+    else
+    {	t = new TypeAArray(t, ti);
+	t->mod = mod;
+    }
+    return t;
+}
+
+d_uns64 TypeAArray::size(Loc loc)
+{
+    return PTRSIZE /* * 2*/;
+}
+
+
+Type *TypeAArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+    {
+	Expression *e;
+	Type *t;
+	Dsymbol *s;
+
+	index->resolve(loc, sc, &e, &t, &s);
+	if (e)
+	{   // It was an expression -
+	    // Rewrite as a static array
+	    TypeSArray *tsa;
+
+	    tsa = new TypeSArray(next, e);
+	    return tsa->semantic(loc,sc);
+	}
+	else if (t)
+	    index = t;
+	else
+	    index->error(loc, "index is not a type or an expression");
+    }
+    else
+	index = index->semantic(loc,sc);
+
+    if (index->nextOf() && !index->nextOf()->isInvariant())
+    {
+	index = index->constOf()->mutableOf();
+    }
+
+    switch (index->toBasetype()->ty)
+    {
+	case Tbool:
+	case Tfunction:
+	case Tvoid:
+	case Tnone:
+	    error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
+	    break;
+    }
+    next = next->semantic(loc,sc);
+    if (mod == MODconst && !next->isInvariant())
+	next = next->constOf();
+    else if (mod == MODinvariant)
+	next = next->invariantOf();
+
+    switch (next->toBasetype()->ty)
+    {
+	case Tfunction:
+	case Tnone:
+	    error(loc, "can't have associative array of %s", next->toChars());
+	    break;
+    }
+    if (next->isauto())
+	error(loc, "cannot have array of auto %s", next->toChars());
+
+    return merge();
+}
+
+void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    //printf("TypeAArray::resolve() %s\n", toChars());
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+    {
+	Expression *e;
+	Type *t;
+	Dsymbol *s;
+
+	index->resolve(loc, sc, &e, &t, &s);
+	if (e)
+	{   // It was an expression -
+	    // Rewrite as a static array
+
+	    TypeSArray *tsa = new TypeSArray(next, e);
+	    return tsa->resolve(loc, sc, pe, pt, ps);
+	}
+	else if (t)
+	    index = t;
+	else
+	    index->error(loc, "index is not a type or an expression");
+    }
+    Type::resolve(loc, sc, pe, pt, ps);
+}
+
+
+Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	Expression *ec;
+	Expressions *arguments;
+
+	//LDC: Build arguments.
+	static FuncDeclaration *aaLen_fd = NULL;
+	if(!aaLen_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
+	    aaLen_fd = FuncDeclaration::genCfunc(args, Type::tsize_t, Id::aaLen);
+	}
+
+	ec = new VarExp(0, aaLen_fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = ((TypeFunction *)aaLen_fd->type)->next;
+    }
+    else if (ident == Id::keys)
+    {
+	Expression *ec;
+	Expressions *arguments;
+	int size = index->size(e->loc);
+
+	assert(size);
+	//LDC: Build arguments.
+	static FuncDeclaration *aaKeys_fd = NULL;
+	if(!aaKeys_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
+	    aaKeys_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaKeys);
+	}
+
+	ec = new VarExp(0, aaKeys_fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	arguments->push(new IntegerExp(0, size, Type::tsize_t));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = index->arrayOf();
+    }
+    else if (ident == Id::values)
+    {
+	Expression *ec;
+	Expressions *arguments;
+
+	//LDC: Build arguments.
+	static FuncDeclaration *aaValues_fd = NULL;
+	if(!aaValues_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
+	    args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
+	    aaValues_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaValues);
+	}
+
+	ec = new VarExp(0, aaValues_fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	size_t keysize = index->size(e->loc);
+	keysize = (keysize + 4 - 1) & ~(4 - 1);
+	arguments->push(new IntegerExp(0, keysize, Type::tsize_t));
+	arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::rehash)
+    {
+	Expression *ec;
+	Expressions *arguments;
+
+	//LDC: Build arguments.
+	static FuncDeclaration *aaRehash_fd = NULL;
+	if(!aaRehash_fd) {
+	    Arguments* args = new Arguments;
+	    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
+	    args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
+	    aaRehash_fd = FuncDeclaration::genCfunc(args, Type::tvoidptr, Id::aaRehash);
+	}
+
+	ec = new VarExp(0, aaRehash_fd);
+	arguments = new Expressions();
+	arguments->push(e->addressOf(sc));
+    arguments->push(index->getTypeInfo(sc));   // LDC, we don't support the getInternalTypeInfo
+                                               // optimization arbitrarily, not yet at least...   
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = this;
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    Type::toDecoBuffer(buf, flag);
+    index->toDecoBuffer(buf);
+    next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
+}
+
+void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+    buf->writeByte('[');
+    index->toCBuffer2(buf, hgs, 0);
+    buf->writeByte(']');
+}
+
+Expression *TypeAArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeAArray::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypeAArray::isZeroInit()
+{
+    return 1;
+}
+
+int TypeAArray::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeAArray::hasPointers()
+{
+    return TRUE;
+}
+
+MATCH TypeAArray::implicitConvTo(Type *to)
+{
+    //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+    if (equals(to))
+	return MATCHexact;
+
+    if (to->ty == Taarray)
+    {	TypeAArray *ta = (TypeAArray *)to;
+
+	if (!(next->mod == ta->next->mod || ta->next->mod == MODconst))
+	    return MATCHnomatch;	// not const-compatible
+
+	if (!(index->mod == ta->index->mod || ta->index->mod == MODconst))
+	    return MATCHnomatch;	// not const-compatible
+
+	MATCH m = next->constConv(ta->next);
+	MATCH mi = index->constConv(ta->index);
+	if (m != MATCHnomatch && mi != MATCHnomatch)
+	{
+	    if (m == MATCHexact && mod != to->mod)
+		m = MATCHconst;
+	    if (mi < m)
+		m = mi;
+	    return m;
+	}
+    }
+    return Type::implicitConvTo(to);
+}
+
+MATCH TypeAArray::constConv(Type *to)
+{
+    if (to->ty == Taarray)
+    {
+	TypeAArray *taa = (TypeAArray *)to;
+	MATCH mindex = index->constConv(taa->index);
+	MATCH mkey = next->constConv(taa->next);
+	// Pick the worst match
+	return mkey < mindex ? mkey : mindex;
+    }
+    else
+	return Type::constConv(to);
+}
+
+/***************************** TypePointer *****************************/
+
+TypePointer::TypePointer(Type *t)
+    : TypeNext(Tpointer, t)
+{
+}
+
+Type *TypePointer::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+    {	t = new TypePointer(t);
+	t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypePointer::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypePointer::semantic()\n");
+    Type *n = next->semantic(loc, sc);
+    switch (n->toBasetype()->ty)
+    {
+	case Ttuple:
+	    error(loc, "can't have pointer to %s", n->toChars());
+	    n = tint32;
+	    break;
+    }
+    if (n != next)
+	deco = NULL;
+    next = n;
+    if (mod == MODconst && !next->isInvariant())
+	next = next->constOf();
+    else if (mod == MODinvariant)
+	next = next->invariantOf();
+    return merge();
+}
+
+
+d_uns64 TypePointer::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    //printf("TypePointer::toCBuffer2() next = %d\n", next->ty);
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+    if (next->ty != Tfunction)
+	buf->writeByte('*');
+}
+
+MATCH TypePointer::implicitConvTo(Type *to)
+{
+    //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
+
+    if (equals(to))
+	return MATCHexact;
+    if (to->ty == Tpointer)
+    {	TypePointer *tp = (TypePointer *)to;
+	assert(tp->next);
+
+        if (!(next->mod == tp->next->mod || tp->next->mod == MODconst))
+            return MATCHnomatch;        // not const-compatible
+
+        /* Alloc conversion to void[]
+         */
+        if (next->ty != Tvoid && tp->next->ty == Tvoid)
+        {
+            return MATCHconvert;
+        }
+
+        MATCH m = next->constConv(tp->next);
+        if (m != MATCHnomatch)
+	{
+	    if (m == MATCHexact && mod != to->mod)
+		m = MATCHconst;
+            return m;
+	}
+
+        /* Conversion of ptr to derived to ptr to base
+         */
+	int offset = 0;
+        if (tp->next->isBaseOf(next, &offset) && offset == 0)
+            return MATCHconvert;
+    }
+    return MATCHnomatch;
+}
+
+int TypePointer::isscalar()
+{
+    return TRUE;
+}
+
+Expression *TypePointer::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypePointer::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypePointer::isZeroInit()
+{
+    return 1;
+}
+
+int TypePointer::hasPointers()
+{
+    return TRUE;
+}
+
+
+/***************************** TypeReference *****************************/
+
+TypeReference::TypeReference(Type *t)
+    : TypeNext(Treference, t)
+{
+    // BUG: what about references to static arrays?
+}
+
+Type *TypeReference::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+    {	t = new TypeReference(t);
+	t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypeReference::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeReference::semantic()\n");
+    Type *n = next->semantic(loc, sc);
+    if (n != next)
+	deco = NULL;
+    next = n;
+    if (mod == MODconst && !next->isInvariant())
+	next = next->constOf();
+    else if (mod == MODinvariant)
+	next = next->invariantOf();
+    return merge();
+}
+
+
+d_uns64 TypeReference::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+    buf->writeByte('&');
+}
+
+Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    // References just forward things along
+    return next->dotExp(sc, e, ident);
+}
+
+Expression *TypeReference::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeReference::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypeReference::isZeroInit()
+{
+    return 1;
+}
+
+
+/***************************** TypeFunction *****************************/
+
+TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage)
+    : TypeNext(Tfunction, treturn)
+{
+//if (!treturn) *(char*)0=0;
+//    assert(treturn);
+    assert(0 <= varargs && varargs <= 2);
+    this->parameters = parameters;
+    this->varargs = varargs;
+    this->linkage = linkage;
+    this->inuse = 0;
+    this->isnothrow = false;
+    this->ispure = false;
+    this->isref = false;
+    this->retInPtr = false;
+    this->usesThis = false;
+    this->usesNest = false;
+    this->retAttrs = 0;
+    this->thisAttrs = 0;
+    this->reverseParams = false;
+    this->reverseIndex = 0;
+}
+
+Type *TypeFunction::syntaxCopy()
+{
+    Type *treturn = next ? next->syntaxCopy() : NULL;
+    Arguments *params = Argument::arraySyntaxCopy(parameters);
+    TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
+    t->mod = mod;
+    t->isnothrow = isnothrow;
+    t->ispure = ispure;
+    t->isref = isref;
+    t->retInPtr = retInPtr;
+    t->usesThis = usesThis;
+    t->usesNest = usesNest;
+    t->retAttrs = retAttrs;
+    t->thisAttrs = thisAttrs;
+    t->reverseParams = reverseParams;
+    t->reverseIndex = reverseIndex;
+    return t;
+}
+
+/*******************************
+ * Returns:
+ *	0	types are distinct
+ *	1	this is covariant with t
+ *	2	arguments match as far as overloading goes,
+ *		but types are not covariant
+ *	3	cannot determine covariance because of forward references
+ */
+
+int Type::covariant(Type *t)
+{
+#if 0
+    printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars());
+    printf("deco = %p, %p\n", deco, t->deco);
+//    printf("ty = %d\n", next->ty);
+#endif
+
+    int inoutmismatch = 0;
+
+    TypeFunction *t1;
+    TypeFunction *t2;
+
+    if (equals(t))
+	return 1;			// covariant
+
+    if (ty != Tfunction || t->ty != Tfunction)
+	goto Ldistinct;
+
+    t1 = (TypeFunction *)this;
+    t2 = (TypeFunction *)t;
+
+    if (t1->varargs != t2->varargs)
+	goto Ldistinct;
+
+    if (t1->parameters && t2->parameters)
+    {
+	size_t dim = Argument::dim(t1->parameters);
+	if (dim != Argument::dim(t2->parameters))
+	    goto Ldistinct;
+
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg1 = Argument::getNth(t1->parameters, i);
+	    Argument *arg2 = Argument::getNth(t2->parameters, i);
+
+	    if (!arg1->type->equals(arg2->type))
+		goto Ldistinct;
+	    if (arg1->storageClass != arg2->storageClass)
+		inoutmismatch = 1;
+	}
+    }
+    else if (t1->parameters != t2->parameters)
+	goto Ldistinct;
+
+    // The argument lists match
+    if (inoutmismatch)
+	goto Lnotcovariant;
+    if (t1->linkage != t2->linkage)
+	goto Lnotcovariant;
+
+  {
+    // Return types
+    Type *t1n = t1->next;
+    Type *t2n = t2->next;
+
+    if (t1n->equals(t2n))
+	goto Lcovariant;
+    if (t1n->ty == Tclass && t2n->ty == Tclass)
+    {
+	/* If same class type, but t2n is const, then it's
+	 * covariant. Do this test first because it can work on
+	 * forward references.
+	 */
+	if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
+	    t2n->mod == MODconst)
+	    goto Lcovariant;
+
+	// If t1n is forward referenced:
+	ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
+	if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
+	{
+	    return 3;
+	}
+    }
+    if (t1n->implicitConvTo(t2n))
+	goto Lcovariant;
+  }
+    goto Lnotcovariant;
+
+Lcovariant:
+    /* Can convert pure to impure, and nothrow to throw
+     */
+    if (!t1->ispure && t2->ispure)
+	goto Lnotcovariant;
+
+    if (!t1->isnothrow && t2->isnothrow)
+	goto Lnotcovariant;
+
+    if (t1->isref != t2->isref)
+	goto Lnotcovariant;
+
+    //printf("\tcovaraint: 1\n");
+    return 1;
+
+Ldistinct:
+    //printf("\tcovaraint: 0\n");
+    return 0;
+
+Lnotcovariant:
+    //printf("\tcovaraint: 2\n");
+    return 2;
+}
+
+void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag)
+{   unsigned char mc;
+
+    //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
+    //static int nest; if (++nest == 50) *(char*)0=0;
+    if (inuse)
+    {	inuse = 2;		// flag error to caller
+	return;
+    }
+    inuse++;
+#if 1
+    if (mod & MODshared)
+	buf->writeByte('O');
+    if (mod & MODconst)
+	buf->writeByte('x');
+    else if (mod & MODinvariant)
+	buf->writeByte('y');
+#endif
+    switch (linkage)
+    {
+	case LINKd:		mc = 'F';	break;
+	case LINKc:		mc = 'U';	break;
+	case LINKwindows:	mc = 'W';	break;
+	case LINKpascal:	mc = 'V';	break;
+	case LINKcpp:		mc = 'R';	break;
+
+    // LDC
+    case LINKintrinsic: mc = 'Q';   break;
+
+	default:
+	    assert(0);
+    }
+    buf->writeByte(mc);
+    if (ispure || isnothrow || isref)
+    {
+	if (ispure)
+	    buf->writestring("Na");
+	if (isnothrow)
+	    buf->writestring("Nb");
+	if (isref)
+	    buf->writestring("Nc");
+    }
+    // Write argument types
+    Argument::argsToDecoBuffer(buf, parameters);
+    //if (buf->data[buf->offset - 1] == '@') halt();
+    buf->writeByte('Z' - varargs);	// mark end of arg list
+    next->toDecoBuffer(buf);
+    inuse--;
+}
+
+void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    //printf("TypeFunction::toCBuffer() this = %p %s\n", this, toChars());
+    const char *p = NULL;
+
+    if (inuse)
+    {	inuse = 2;		// flag error to caller
+	return;
+    }
+    inuse++;
+
+    /* Use 'storage class' style for attributes
+     */
+    if (mod & MODconst)
+	buf->writestring("const ");
+    if (mod & MODinvariant)
+	buf->writestring("invariant ");
+    if (mod & MODshared)
+	buf->writestring("shared ");
+
+    if (ispure)
+	buf->writestring("pure ");
+    if (isnothrow)
+	buf->writestring("nothrow ");
+    if (isref)
+	buf->writestring("ref ");
+
+    if (next && (!ident || ident->toHChars2() == ident->toChars()))
+	next->toCBuffer2(buf, hgs, 0);
+    if (hgs->ddoc != 1)
+    {
+	switch (linkage)
+	{
+	    case LINKd:		p = NULL;	break;
+	    case LINKc:		p = "C ";	break;
+	    case LINKwindows:	p = "Windows ";	break;
+	    case LINKpascal:	p = "Pascal ";	break;
+	    case LINKcpp:	p = "C++ ";	break;
+
+        // LDC
+        case LINKintrinsic: p = "Intrinsic"; break;
+
+	    default:
+		assert(0);
+	}
+    }
+
+    if (!hgs->hdrgen && p)
+	buf->writestring(p);
+    if (ident)
+    {   buf->writeByte(' ');
+	buf->writestring(ident->toHChars2());
+    }
+    Argument::argsToCBuffer(buf, hgs, parameters, varargs);
+    inuse--;
+}
+
+void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    //printf("TypeFunction::toCBuffer2() this = %p %s\n", this, toChars());
+    const char *p = NULL;
+
+    if (inuse)
+    {	inuse = 2;		// flag error to caller
+	return;
+    }
+    inuse++;
+    if (next)
+	next->toCBuffer2(buf, hgs, 0);
+    if (hgs->ddoc != 1)
+    {
+	switch (linkage)
+	{
+	    case LINKd:		p = NULL;	break;
+	    case LINKc:		p = "C ";	break;
+	    case LINKwindows:	p = "Windows ";	break;
+	    case LINKpascal:	p = "Pascal ";	break;
+	    case LINKcpp:	p = "C++ ";	break;
+
+        // LDC
+        case LINKintrinsic: p = "Intrinsic"; break;
+
+	    default:
+		assert(0);
+	}
+    }
+
+    if (!hgs->hdrgen && p)
+	buf->writestring(p);
+    buf->writestring(" function");
+    Argument::argsToCBuffer(buf, hgs, parameters, varargs);
+
+    /* Use postfix style for attributes
+     */
+    if (mod != this->mod)
+    {
+	if (mod & MODconst)
+	    buf->writestring(" const");
+	if (mod & MODinvariant)
+	    buf->writestring(" invariant");
+	if (mod & MODshared)
+	    buf->writestring(" shared");
+    }
+    if (ispure)
+	buf->writestring(" pure");
+    if (isnothrow)
+	buf->writestring(" nothrow");
+    if (isref)
+	buf->writestring(" ref");
+
+    inuse--;
+}
+
+Type *TypeFunction::semantic(Loc loc, Scope *sc)
+{
+    if (deco)			// if semantic() already run
+    {
+	//printf("already done\n");
+	return this;
+    }
+    //printf("TypeFunction::semantic() this = %p\n", this);
+
+    TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction));
+    memcpy(tf, this, sizeof(TypeFunction));
+    if (parameters)
+    {	tf->parameters = (Arguments *)parameters->copy();
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   Argument *arg = (Argument *)parameters->data[i];
+	    Argument *cpy = (Argument *)mem.malloc(sizeof(Argument));
+	    memcpy(cpy, arg, sizeof(Argument));
+	    tf->parameters->data[i] = (void *)cpy;
+	}
+    }
+
+    if (sc->stc & STCpure)
+	tf->ispure = TRUE;
+    if (sc->stc & STCnothrow)
+	tf->isnothrow = TRUE;
+    if (sc->stc & STCref)
+	tf->isref = TRUE;
+
+    tf->linkage = sc->linkage;
+    if (!tf->next)
+    {
+	assert(global.errors);
+	tf->next = tvoid;
+    }
+    tf->next = tf->next->semantic(loc,sc);
+    if (tf->next->toBasetype()->ty == Tsarray)
+    {	error(loc, "functions cannot return static array %s", tf->next->toChars());
+	tf->next = Type::terror;
+    }
+    if (tf->next->toBasetype()->ty == Tfunction)
+    {	error(loc, "functions cannot return a function");
+	tf->next = Type::terror;
+    }
+    if (tf->next->toBasetype()->ty == Ttuple)
+    {	error(loc, "functions cannot return a tuple");
+	tf->next = Type::terror;
+    }
+    if (tf->next->isauto() && !(sc->flags & SCOPEctor))
+	error(loc, "functions cannot return auto %s", tf->next->toChars());
+
+    if (tf->parameters)
+    {	size_t dim = Argument::dim(tf->parameters);
+
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg = Argument::getNth(tf->parameters, i);
+
+	    tf->inuse++;
+	    arg->type = arg->type->semantic(loc,sc);
+	    if (tf->inuse == 1) tf->inuse--;
+
+	    if (arg->storageClass & (STCconst | STCin))
+	    {
+		if (!arg->type->isInvariant())
+		    arg->type = arg->type->constOf();
+	    }
+	    else if (arg->storageClass & STCinvariant)
+		arg->type = arg->type->invariantOf();
+
+	    if (arg->storageClass & (STCauto | STCalias | STCstatic))
+	    {
+		if (!arg->type)
+		    continue;
+	    }
+
+	    Type *t = arg->type->toBasetype();
+
+	    if (arg->storageClass & (STCout | STCref | STClazy))
+	    {
+		if (t->ty == Tsarray)
+		    error(loc, "cannot have out or ref parameter of type %s", t->toChars());
+		if (arg->storageClass & STCout && arg->type->mod)
+		    error(loc, "cannot have const/invariant out parameter of type %s", t->toChars());
+	    }
+	    if (!(arg->storageClass & STClazy) && t->ty == Tvoid)
+		error(loc, "cannot have parameter of type %s", arg->type->toChars());
+
+	    if (arg->defaultArg)
+	    {
+		arg->defaultArg = arg->defaultArg->semantic(sc);
+		arg->defaultArg = resolveProperties(sc, arg->defaultArg);
+		arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type);
+
+		// make sure default arguments only use variables with lower protection
+		// this check only catches the common case that the default arg Exp is a VarExp
+		if(arg->defaultArg->op == TOKvar)
+		{   VarExp *ve = (VarExp *)arg->defaultArg;
+		    if(ve->var->protection != PROTundefined && ve->var->protection < sc->protection)
+			error(loc, "default argument %s has stronger protection than function %s", ve->var->toChars(), toChars());
+		}
+	    }
+
+	    /* If arg turns out to be a tuple, the number of parameters may
+	     * change.
+	     */
+	    if (t->ty == Ttuple)
+	    {	dim = Argument::dim(tf->parameters);
+		i--;
+	    }
+	}
+    }
+    tf->deco = tf->merge()->deco;
+
+    if (tf->inuse)
+    {	error(loc, "recursive type");
+	tf->inuse = 0;
+	return terror;
+    }
+
+    if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0)
+	error(loc, "variadic functions with non-D linkage must have at least one parameter");
+
+    /* Don't return merge(), because arg identifiers and default args
+     * can be different
+     * even though the types match
+     */
+    return tf;
+}
+
+/********************************
+ * 'args' are being matched to function 'this'
+ * Determine match level.
+ * Returns:
+ *	MATCHxxxx
+ */
+
+int TypeFunction::callMatch(Expression *ethis, Expressions *args)
+{
+    //printf("TypeFunction::callMatch() %s\n", toChars());
+    MATCH match = MATCHexact;		// assume exact match
+
+    if (ethis)
+    {	Type *t = ethis->type;
+	if (t->toBasetype()->ty == Tpointer)
+	    t = t->toBasetype()->nextOf();	// change struct* to struct
+	if (t->mod != mod)
+	{
+	    if (mod == MODconst)
+		match = MATCHconst;
+	    else
+		return MATCHnomatch;
+	}
+    }
+
+    size_t nparams = Argument::dim(parameters);
+    size_t nargs = args ? args->dim : 0;
+    if (nparams == nargs)
+	;
+    else if (nargs > nparams)
+    {
+	if (varargs == 0)
+	    goto Nomatch;		// too many args; no match
+	match = MATCHconvert;		// match ... with a "conversion" match level
+    }
+
+    for (size_t u = 0; u < nparams; u++)
+    {	MATCH m;
+	Expression *arg;
+
+	// BUG: what about out and ref?
+
+	Argument *p = Argument::getNth(parameters, u);
+	assert(p);
+	if (u >= nargs)
+	{
+	    if (p->defaultArg)
+		continue;
+	    if (varargs == 2 && u + 1 == nparams)
+		goto L1;
+	    goto Nomatch;		// not enough arguments
+	}
+	arg = (Expression *)args->data[u];
+	assert(arg);
+
+	// Non-lvalues do not match ref or out parameters
+	if (p->storageClass & (STCref | STCout) && !arg->isLvalue())
+	    goto Nomatch;
+
+	if (p->storageClass & STClazy && p->type->ty == Tvoid &&
+		arg->type->ty != Tvoid)
+	    m = MATCHconvert;
+	else
+	    m = arg->implicitConvTo(p->type);
+	//printf("\tm = %d\n", m);
+	if (m == MATCHnomatch)			// if no match
+	{
+	  L1:
+	    if (varargs == 2 && u + 1 == nparams)	// if last varargs param
+	    {	Type *tb = p->type->toBasetype();
+		TypeSArray *tsa;
+		integer_t sz;
+
+		switch (tb->ty)
+		{
+		    case Tsarray:
+			tsa = (TypeSArray *)tb;
+			sz = tsa->dim->toInteger();
+			if (sz != nargs - u)
+			    goto Nomatch;
+		    case Tarray:
+		    {	TypeArray *ta = (TypeArray *)tb;
+			for (; u < nargs; u++)
+			{
+			    arg = (Expression *)args->data[u];
+			    assert(arg);
+#if 1
+			    /* If lazy array of delegates,
+			     * convert arg(s) to delegate(s)
+			     */
+			    Type *tret = p->isLazyArray();
+			    if (tret)
+			    {
+				if (ta->next->equals(arg->type))
+				{   m = MATCHexact;
+				}
+				else
+				{
+				    m = arg->implicitConvTo(tret);
+				    if (m == MATCHnomatch)
+				    {
+					if (tret->toBasetype()->ty == Tvoid)
+					    m = MATCHconvert;
+				    }
+				}
+			    }
+			    else
+				m = arg->implicitConvTo(ta->next);
+#else
+			    m = arg->implicitConvTo(ta->next);
+#endif
+			    if (m == MATCHnomatch)
+				goto Nomatch;
+			    if (m < match)
+				match = m;
+			}
+			goto Ldone;
+		    }
+		    case Tclass:
+			// Should see if there's a constructor match?
+			// Or just leave it ambiguous?
+			goto Ldone;
+
+		    default:
+			goto Nomatch;
+		}
+	    }
+	    goto Nomatch;
+	}
+	if (m < match)
+	    match = m;			// pick worst match
+    }
+
+Ldone:
+    //printf("match = %d\n", match);
+    return match;
+
+Nomatch:
+    //printf("no match\n");
+    return MATCHnomatch;
+}
+
+Type *TypeFunction::reliesOnTident()
+{
+    if (parameters)
+    {
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   Argument *arg = (Argument *)parameters->data[i];
+	    Type *t = arg->type->reliesOnTident();
+	    if (t)
+		return t;
+	}
+    }
+    return next->reliesOnTident();
+}
+
+/***************************** TypeDelegate *****************************/
+
+TypeDelegate::TypeDelegate(Type *t)
+    : TypeNext(Tfunction, t)
+{
+    ty = Tdelegate;
+}
+
+Type *TypeDelegate::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+    {	t = new TypeDelegate(t);
+	t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypeDelegate::semantic(Loc loc, Scope *sc)
+{
+    if (deco)			// if semantic() already run
+    {
+	//printf("already done\n");
+	return this;
+    }
+    next = next->semantic(loc,sc);
+    return merge();
+}
+
+d_uns64 TypeDelegate::size(Loc loc)
+{
+    return PTRSIZE * 2;
+}
+
+void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    TypeFunction *tf = (TypeFunction *)next;
+
+    tf->next->toCBuffer2(buf, hgs, 0);
+    buf->writestring(" delegate");
+    Argument::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs);
+}
+
+Expression *TypeDelegate::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeDelegate::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypeDelegate::isZeroInit()
+{
+    return 1;
+}
+
+int TypeDelegate::checkBoolean()
+{
+    return TRUE;
+}
+
+Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::ptr)
+    {
+    e = new GEPExp(e->loc, e, ident, 0);
+	e->type = tvoidptr;
+	return e;
+    }
+    else if (ident == Id::funcptr)
+    {
+    e = new GEPExp(e->loc, e, ident, 1);
+    e->type = tvoidptr;
+	return e;
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeDelegate::hasPointers()
+{
+    return TRUE;
+}
+
+
+
+/***************************** TypeQualified *****************************/
+
+TypeQualified::TypeQualified(TY ty, Loc loc)
+    : Type(ty)
+{
+    this->loc = loc;
+}
+
+void TypeQualified::syntaxCopyHelper(TypeQualified *t)
+{
+    //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
+    idents.setDim(t->idents.dim);
+    for (int i = 0; i < idents.dim; i++)
+    {
+	Identifier *id = (Identifier *)t->idents.data[i];
+	if (id->dyncast() == DYNCAST_DSYMBOL)
+	{
+	    TemplateInstance *ti = (TemplateInstance *)id;
+
+	    ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+	    id = (Identifier *)ti;
+	}
+	idents.data[i] = id;
+    }
+}
+
+
+void TypeQualified::addIdent(Identifier *ident)
+{
+    idents.push(ident);
+}
+
+void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs)
+{
+    int i;
+
+    for (i = 0; i < idents.dim; i++)
+    {	Identifier *id = (Identifier *)idents.data[i];
+
+	buf->writeByte('.');
+
+	if (id->dyncast() == DYNCAST_DSYMBOL)
+	{
+	    TemplateInstance *ti = (TemplateInstance *)id;
+	    ti->toCBuffer(buf, hgs);
+	}
+	else
+	    buf->writestring(id->toChars());
+    }
+}
+
+d_uns64 TypeQualified::size(Loc loc)
+{
+    error(this->loc, "size of type %s is not known", toChars());
+    return 1;
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *	if expression, *pe is set
+ *	if type, *pt is set
+ */
+
+void TypeQualified::resolveHelper(Loc loc, Scope *sc,
+	Dsymbol *s, Dsymbol *scopesym,
+	Expression **pe, Type **pt, Dsymbol **ps)
+{
+    VarDeclaration *v;
+    EnumMember *em;
+    TupleDeclaration *td;
+    Expression *e;
+
+#if 0
+    printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars());
+    if (scopesym)
+	printf("\tscopesym = '%s'\n", scopesym->toChars());
+#endif
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+    if (s)
+    {
+	//printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	s->checkDeprecated(loc, sc);		// check for deprecated aliases
+	s = s->toAlias();
+	//printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id = (Identifier *)idents.data[i];
+	    Dsymbol *sm = s->searchX(loc, sc, id);
+	    //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	    //printf("\tgetType = '%s'\n", s->getType()->toChars());
+	    if (!sm)
+	    {	Type *t;
+
+		v = s->isVarDeclaration();
+		if (v && id == Id::length)
+		{
+		    e = v->getConstInitializer();
+		    if (!e)
+			e = new VarExp(loc, v);
+		    t = e->type;
+		    if (!t)
+			goto Lerror;
+		    goto L3;
+		}
+		t = s->getType();
+		if (!t && s->isDeclaration())
+		    t = s->isDeclaration()->type;
+		if (t)
+		{
+		    sm = t->toDsymbol(sc);
+		    if (sm)
+		    {	sm = sm->search(loc, id, 0);
+			if (sm)
+			    goto L2;
+		    }
+		    //e = t->getProperty(loc, id);
+		    e = new TypeExp(loc, t);
+		    e = t->dotExp(sc, e, id);
+		    i++;
+		L3:
+		    for (; i < idents.dim; i++)
+		    {
+			id = (Identifier *)idents.data[i];
+			//printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type);
+			if (id == Id::offsetof)
+			{   e = new DotIdExp(e->loc, e, id);
+			    e = e->semantic(sc);
+			}
+			else
+			    e = e->type->dotExp(sc, e, id);
+		    }
+		    *pe = e;
+		}
+		else
+	          Lerror:
+		    error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
+		return;
+	    }
+	L2:
+	    s = sm->toAlias();
+	}
+
+	v = s->isVarDeclaration();
+	if (v)
+	{
+#if 0
+	    // It's not a type, it's an expression
+	    Expression *e = v->getConstInitializer();
+	    if (e)
+	    {
+		*pe = e->copy();	// make copy so we can change loc
+		(*pe)->loc = loc;
+	    }
+	    else
+#endif
+	    {
+#if 0
+		WithScopeSymbol *withsym;
+		if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL)
+		{
+		    // Same as wthis.ident
+		    e = new VarExp(loc, withsym->withstate->wthis);
+		    e = new DotIdExp(loc, e, ident);
+		    //assert(0);	// BUG: should handle this
+		}
+		else
+#endif
+		    *pe = new VarExp(loc, v);
+	    }
+	    return;
+	}
+	em = s->isEnumMember();
+	if (em)
+	{
+	    // It's not a type, it's an expression
+	    *pe = em->value->copy();
+	    return;
+	}
+
+L1:
+	Type *t = s->getType();
+	if (!t)
+	{
+	    // If the symbol is an import, try looking inside the import
+	    Import *si;
+
+	    si = s->isImport();
+	    if (si)
+	    {
+		s = si->search(loc, s->ident, 0);
+		if (s && s != si)
+		    goto L1;
+		s = si;
+	    }
+	    *ps = s;
+	    return;
+	}
+	if (t->ty == Tinstance && t != this && !t->deco)
+	{   error(loc, "forward reference to '%s'", t->toChars());
+	    return;
+	}
+
+	if (t != this)
+	{
+	    if (t->reliesOnTident())
+	    {
+		Scope *scx;
+
+		for (scx = sc; 1; scx = scx->enclosing)
+		{
+		    if (!scx)
+		    {   error(loc, "forward reference to '%s'", t->toChars());
+			return;
+		    }
+		    if (scx->scopesym == scopesym)
+			break;
+		}
+		t = t->semantic(loc, scx);
+		//((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps);
+	    }
+	}
+	if (t->ty == Ttuple)
+	    *pt = t->syntaxCopy();
+	else
+	    *pt = t->merge();
+    }
+    if (!s)
+    {
+	error(loc, "identifier '%s' is not defined", toChars());
+    }
+}
+
+/***************************** TypeIdentifier *****************************/
+
+TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
+    : TypeQualified(Tident, loc)
+{
+    this->ident = ident;
+}
+
+
+Type *TypeIdentifier::syntaxCopy()
+{
+    TypeIdentifier *t;
+
+    t = new TypeIdentifier(loc, ident);
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag)
+{   unsigned len;
+    char *name;
+
+    Type::toDecoBuffer(buf, flag);
+    name = ident->toChars();
+    len = strlen(name);
+    buf->printf("%d%s", len, name);
+}
+
+void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(this->ident->toChars());
+    toCBuffer2Helper(buf, hgs);
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *	if expression, *pe is set
+ *	if type, *pt is set
+ */
+
+void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{   Dsymbol *s;
+    Dsymbol *scopesym;
+
+    //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+    s = sc->search(loc, ident, &scopesym);
+    resolveHelper(loc, sc, s, scopesym, pe, pt, ps);
+    if (*pt && mod)
+    {
+	if (mod & MODconst)
+	    *pt = (*pt)->constOf();
+	else if (mod & MODinvariant)
+	    *pt = (*pt)->invariantOf();
+    }
+}
+
+/*****************************************
+ * See if type resolves to a symbol, if so,
+ * return that symbol.
+ */
+
+Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
+{
+    //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+    if (!sc)
+	return NULL;
+    //printf("ident = '%s'\n", ident->toChars());
+
+    Dsymbol *scopesym;
+    Dsymbol *s = sc->search(loc, ident, &scopesym);
+    if (s)
+    {
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id = (Identifier *)idents.data[i];
+	    s = s->searchX(loc, sc, id);
+	    if (!s)                 // failed to find a symbol
+	    {	//printf("\tdidn't find a symbol\n");
+		break;
+	    }
+	}
+    }
+    return s;
+}
+
+Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeIdentifier::semantic(%s)\n", toChars());
+    resolve(loc, sc, &e, &t, &s);
+    if (t)
+    {
+	//printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
+
+	if (t->ty == Ttypedef)
+	{   TypeTypedef *tt = (TypeTypedef *)t;
+
+	    if (tt->sym->sem == 1)
+		error(loc, "circular reference of typedef %s", tt->toChars());
+	}
+	if (isConst())
+	    t = t->constOf();
+	else if (isInvariant())
+	    t = t->invariantOf();
+    }
+    else
+    {
+#ifdef DEBUG
+	if (!global.gag)
+	    printf("1: ");
+#endif
+	if (s)
+	{
+	    s->error(loc, "is used as a type");
+	    //halt();
+	}
+	else
+	    error(loc, "%s is used as a type", toChars());
+	t = tvoid;
+    }
+    //t->print();
+    return t;
+}
+
+Type *TypeIdentifier::reliesOnTident()
+{
+    return this;
+}
+
+Expression *TypeIdentifier::toExpression()
+{
+    Expression *e = new IdentifierExp(loc, ident);
+    for (int i = 0; i < idents.dim; i++)
+    {
+	Identifier *id = (Identifier *)idents.data[i];
+	e = new DotIdExp(loc, e, id);
+    }
+
+    return e;
+}
+
+/***************************** TypeInstance *****************************/
+
+TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
+    : TypeQualified(Tinstance, loc)
+{
+    this->tempinst = tempinst;
+}
+
+Type *TypeInstance::syntaxCopy()
+{
+    //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
+    TypeInstance *t;
+
+    t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+
+void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    tempinst->toCBuffer(buf, hgs);
+    toCBuffer2Helper(buf, hgs);
+}
+
+void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    // Note close similarity to TypeIdentifier::resolve()
+
+    Dsymbol *s;
+
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+
+#if 0
+    if (!idents.dim)
+    {
+	error(loc, "template instance '%s' has no identifier", toChars());
+	return;
+    }
+#endif
+    //id = (Identifier *)idents.data[0];
+    //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars());
+    s = tempinst;
+    if (s)
+	s->semantic(sc);
+    resolveHelper(loc, sc, s, NULL, pe, pt, ps);
+    if (*pt && mod)
+    {
+	if (mod & MODconst)
+	    *pt = (*pt)->constOf();
+	else if (mod & MODinvariant)
+	    *pt = (*pt)->invariantOf();
+    }
+    //printf("pt = '%s'\n", (*pt)->toChars());
+}
+
+Type *TypeInstance::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeInstance::semantic(%s)\n", toChars());
+
+    if (sc->parameterSpecialization)
+    {
+	unsigned errors = global.errors;
+	global.gag++;
+
+	resolve(loc, sc, &e, &t, &s);
+
+	global.gag--;
+	if (errors != global.errors)
+	{   if (global.gag == 0)
+		global.errors = errors;
+	    return this;
+	}
+    }
+    else
+	resolve(loc, sc, &e, &t, &s);
+
+    if (!t)
+    {
+#ifdef DEBUG
+	printf("2: ");
+#endif
+	error(loc, "%s is used as a type", toChars());
+	t = tvoid;
+    }
+    return t;
+}
+
+
+/***************************** TypeTypeof *****************************/
+
+TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
+	: TypeQualified(Ttypeof, loc)
+{
+    this->exp = exp;
+}
+
+Type *TypeTypeof::syntaxCopy()
+{
+    TypeTypeof *t;
+
+    t = new TypeTypeof(loc, exp->syntaxCopy());
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
+{
+    Type *t;
+
+    t = semantic(loc, sc);
+    if (t == this)
+	return NULL;
+    return t->toDsymbol(sc);
+}
+
+void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring("typeof(");
+    exp->toCBuffer(buf, hgs);
+    buf->writeByte(')');
+    toCBuffer2Helper(buf, hgs);
+}
+
+Type *TypeTypeof::semantic(Loc loc, Scope *sc)
+{   Expression *e;
+    Type *t;
+
+    //printf("TypeTypeof::semantic() %p\n", this);
+
+    //static int nest; if (++nest == 50) *(char*)0=0;
+
+#if 0
+    /* Special case for typeof(this) and typeof(super) since both
+     * should work even if they are not inside a non-static member function
+     */
+    if (exp->op == TOKthis || exp->op == TOKsuper)
+    {
+	// Find enclosing struct or class
+	for (Dsymbol *s = sc->parent; 1; s = s->parent)
+	{
+	    ClassDeclaration *cd;
+	    StructDeclaration *sd;
+
+	    if (!s)
+	    {
+		error(loc, "%s is not in a struct or class scope", exp->toChars());
+		goto Lerr;
+	    }
+	    cd = s->isClassDeclaration();
+	    if (cd)
+	    {
+		if (exp->op == TOKsuper)
+		{
+		    cd = cd->baseClass;
+		    if (!cd)
+		    {	error(loc, "class %s has no 'super'", s->toChars());
+			goto Lerr;
+		    }
+		}
+		t = cd->type;
+		break;
+	    }
+	    sd = s->isStructDeclaration();
+	    if (sd)
+	    {
+		if (exp->op == TOKsuper)
+		{
+		    error(loc, "struct %s has no 'super'", sd->toChars());
+		    goto Lerr;
+		}
+		t = sd->type->pointerTo();
+		break;
+	    }
+	}
+    }
+    else
+#endif
+    {
+	sc->intypeof++;
+	exp = exp->semantic(sc);
+	sc->intypeof--;
+	if (exp->op == TOKtype)
+	{
+	    error(loc, "argument %s to typeof is not an expression", exp->toChars());
+	}
+	t = exp->type;
+	if (!t)
+	{
+	    error(loc, "expression (%s) has no type", exp->toChars());
+	    goto Lerr;
+	}
+	if (t->ty == Ttypeof)
+	    error(loc, "forward reference to %s", toChars());
+
+	/* typeof should reflect the true type,
+	 * not what 'auto' would have gotten us.
+	 */
+	//t = t->toHeadMutable();
+    }
+
+    if (idents.dim)
+    {
+	Dsymbol *s = t->toDsymbol(sc);
+	for (size_t i = 0; i < idents.dim; i++)
+	{
+	    if (!s)
+		break;
+	    Identifier *id = (Identifier *)idents.data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (s)
+	{
+	    t = s->getType();
+	    if (!t)
+	    {	error(loc, "%s is not a type", s->toChars());
+		goto Lerr;
+	    }
+	}
+	else
+	{   error(loc, "cannot resolve .property for %s", toChars());
+	    goto Lerr;
+	}
+    }
+    return t;
+
+Lerr:
+    return tvoid;
+}
+
+d_uns64 TypeTypeof::size(Loc loc)
+{
+    if (exp->type)
+	return exp->type->size(loc);
+    else
+	return TypeQualified::size(loc);
+}
+
+
+
+/***************************** TypeReturn *****************************/
+
+TypeReturn::TypeReturn(Loc loc)
+	: TypeQualified(Treturn, loc)
+{
+}
+
+Type *TypeReturn::syntaxCopy()
+{
+    TypeReturn *t = new TypeReturn(loc);
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+Dsymbol *TypeReturn::toDsymbol(Scope *sc)
+{
+    Type *t = semantic(0, sc);
+    if (t == this)
+	return NULL;
+    return t->toDsymbol(sc);
+}
+
+Type *TypeReturn::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    if (!sc->func)
+    {	error(loc, "typeof(return) must be inside function");
+	goto Lerr;
+    }
+    t = sc->func->type->nextOf();
+
+    if (mod & MODinvariant)
+	t = t->invariantOf();
+    else if (mod & MODconst)
+	t = t->constOf();
+
+    if (idents.dim)
+    {
+	Dsymbol *s = t->toDsymbol(sc);
+	for (size_t i = 0; i < idents.dim; i++)
+	{
+	    if (!s)
+		break;
+	    Identifier *id = (Identifier *)idents.data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (s)
+	{
+	    t = s->getType();
+	    if (!t)
+	    {	error(loc, "%s is not a type", s->toChars());
+		goto Lerr;
+	    }
+	}
+	else
+	{   error(loc, "cannot resolve .property for %s", toChars());
+	    goto Lerr;
+	}
+    }
+    return t;
+
+Lerr:
+    return terror;
+}
+
+void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring("typeof(return)");
+    toCBuffer2Helper(buf, hgs);
+}
+
+
+/***************************** TypeEnum *****************************/
+
+TypeEnum::TypeEnum(EnumDeclaration *sym)
+	: Type(Tenum)
+{
+    this->sym = sym;
+}
+
+char *TypeEnum::toChars()
+{
+    if (mod)
+	return Type::toChars();
+    return sym->toChars();
+}
+
+Type *TypeEnum::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeEnum::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeEnum::semantic() %s\n", toChars());
+    sym->semantic(sc);
+    return merge();
+}
+
+d_uns64 TypeEnum::size(Loc loc)
+{
+    if (!sym->memtype)
+    {
+	error(loc, "enum %s is forward referenced", sym->toChars());
+	return 4;
+    }
+    return sym->memtype->size(loc);
+}
+
+unsigned TypeEnum::alignsize()
+{
+    if (!sym->memtype)
+    {
+#ifdef DEBUG
+	printf("1: ");
+#endif
+	error(0, "enum %s is forward referenced", sym->toChars());
+	return 4;
+    }
+    return sym->memtype->alignsize();
+}
+
+Dsymbol *TypeEnum::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+Type *TypeEnum::toBasetype()
+{
+    if (!sym->memtype)
+    {
+#ifdef DEBUG
+	printf("2: ");
+#endif
+	error(sym->loc, "enum %s is forward referenced", sym->toChars());
+	return tint32;
+    }
+    return sym->memtype->toBasetype();
+}
+
+void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    const char *name = sym->mangle();
+    Type::toDecoBuffer(buf, flag);
+    buf->printf("%s", name);
+}
+
+void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(sym->toChars());
+}
+
+Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
+#endif
+    Dsymbol *s = sym->search(e->loc, ident, 0);
+    if (!s)
+    {
+	return getProperty(e->loc, ident);
+    }
+    EnumMember *m = s->isEnumMember();
+    Expression *em = m->value->copy();
+    em->loc = e->loc;
+    return em;
+}
+
+Expression *TypeEnum::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+    if (ident == Id::max)
+    {
+	if (!sym->maxval)
+	    goto Lfwd;
+	e = sym->maxval;
+    }
+    else if (ident == Id::min)
+    {
+	if (!sym->minval)
+	    goto Lfwd;
+	e = sym->minval;
+    }
+    else if (ident == Id::init)
+    {
+	e = defaultInit(loc);
+    }
+    else
+    {
+	e = toBasetype()->getProperty(loc, ident);
+    }
+    return e;
+
+Lfwd:
+    error(loc, "forward reference of %s.%s", toChars(), ident->toChars());
+    return new IntegerExp(0, 0, this);
+}
+
+int TypeEnum::isintegral()
+{
+    return 1;
+}
+
+int TypeEnum::isfloating()
+{
+    return 0;
+}
+
+int TypeEnum::isunsigned()
+{
+    return sym->memtype->isunsigned();
+}
+
+int TypeEnum::isscalar()
+{
+    return 1;
+    //return sym->memtype->isscalar();
+}
+
+MATCH TypeEnum::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeEnum::implicitConvTo()\n");
+    if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
+	m = (mod == to->mod) ? MATCHexact : MATCHconst;
+    else if (sym->memtype->implicitConvTo(to))
+	m = MATCHconvert;	// match with conversions
+    else
+	m = MATCHnomatch;	// no match
+    return m;
+}
+
+MATCH TypeEnum::constConv(Type *to)
+{
+    if (equals(to))
+	return MATCHexact;
+    if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
+	to->mod == MODconst)
+	return MATCHconst;
+    return MATCHnomatch;
+}
+
+
+Expression *TypeEnum::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeEnum::defaultInit() '%s'\n", toChars());
+#endif
+    // Initialize to first member of enum
+    //printf("%s\n", sym->defaultval->type->toChars());
+    if (!sym->defaultval)
+    {
+	error(loc, "forward reference of %s.init", toChars());
+	return new IntegerExp(0, 0, this);
+    }
+    return sym->defaultval;
+}
+
+int TypeEnum::isZeroInit()
+{
+    return sym->defaultval->isBool(FALSE);
+}
+
+int TypeEnum::hasPointers()
+{
+    return toBasetype()->hasPointers();
+}
+
+/***************************** TypeTypedef *****************************/
+
+TypeTypedef::TypeTypedef(TypedefDeclaration *sym)
+	: Type(Ttypedef)
+{
+    this->sym = sym;
+}
+
+Type *TypeTypedef::syntaxCopy()
+{
+    return this;
+}
+
+char *TypeTypedef::toChars()
+{
+    return Type::toChars();
+}
+
+Type *TypeTypedef::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem);
+    sym->semantic(sc);
+    return merge();
+}
+
+d_uns64 TypeTypedef::size(Loc loc)
+{
+    return sym->basetype->size(loc);
+}
+
+unsigned TypeTypedef::alignsize()
+{
+    return sym->basetype->alignsize();
+}
+
+Dsymbol *TypeTypedef::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+Type *TypeTypedef::toHeadMutable()
+{
+    if (!mod)
+	return this;
+
+    Type *tb = toBasetype();
+    Type *t = tb->toHeadMutable();
+    if (t->equals(tb))
+	return this;
+    else
+	return mutableOf();
+}
+
+void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    Type::toDecoBuffer(buf, flag);
+    const char *name = sym->mangle();
+    buf->printf("%s", name);
+}
+
+void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars());
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(sym->toChars());
+}
+
+Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
+#endif
+    if (ident == Id::init)
+    {
+	return Type::dotExp(sc, e, ident);
+    }
+    return sym->basetype->dotExp(sc, e, ident);
+}
+
+Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeTypedef::getProperty(ident = '%s') '%s'\n", ident->toChars(), toChars());
+#endif
+    if (ident == Id::init)
+    {
+	return Type::getProperty(loc, ident);
+    }
+    return sym->basetype->getProperty(loc, ident);
+}
+
+int TypeTypedef::isintegral()
+{
+    //printf("TypeTypedef::isintegral()\n");
+    //printf("sym = '%s'\n", sym->toChars());
+    //printf("basetype = '%s'\n", sym->basetype->toChars());
+    return sym->basetype->isintegral();
+}
+
+int TypeTypedef::isfloating()
+{
+    return sym->basetype->isfloating();
+}
+
+int TypeTypedef::isreal()
+{
+    return sym->basetype->isreal();
+}
+
+int TypeTypedef::isimaginary()
+{
+    return sym->basetype->isimaginary();
+}
+
+int TypeTypedef::iscomplex()
+{
+    return sym->basetype->iscomplex();
+}
+
+int TypeTypedef::isunsigned()
+{
+    return sym->basetype->isunsigned();
+}
+
+int TypeTypedef::isscalar()
+{
+    return sym->basetype->isscalar();
+}
+
+int TypeTypedef::isAssignable()
+{
+    return sym->basetype->isAssignable();
+}
+
+int TypeTypedef::checkBoolean()
+{
+    return sym->basetype->checkBoolean();
+}
+
+Type *TypeTypedef::toBasetype()
+{
+    if (sym->inuse)
+    {
+	sym->error("circular definition");
+	sym->basetype = Type::terror;
+	return Type::terror;
+    }
+    sym->inuse = 1;
+    Type *t = sym->basetype->toBasetype();
+    sym->inuse = 0;
+    if (mod == MODconst && !t->isInvariant())
+	t = t->constOf();
+    else if (mod == MODinvariant)
+	t = t->invariantOf();
+    return t;
+}
+
+MATCH TypeTypedef::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
+    if (equals(to))
+	m = MATCHexact;		// exact match
+    else if (sym->basetype->implicitConvTo(to))
+	m = MATCHconvert;	// match with conversions
+    else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
+    {
+	m = constConv(to);
+    }
+    else
+	m = MATCHnomatch;	// no match
+    return m;
+}
+
+MATCH TypeTypedef::constConv(Type *to)
+{
+    if (equals(to))
+	return MATCHexact;
+    if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
+	return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype);
+    return MATCHnomatch;
+}
+
+
+Expression *TypeTypedef::defaultInit(Loc loc)
+{   Expression *e;
+    Type *bt;
+
+#if LOGDEFAULTINIT
+    printf("TypeTypedef::defaultInit() '%s'\n", toChars());
+#endif
+    if (sym->init)
+    {
+	//sym->init->toExpression()->print();
+	return sym->init->toExpression();
+    }
+    bt = sym->basetype;
+    e = bt->defaultInit(loc);
+    e->type = this;
+    while (bt->ty == Tsarray)
+    {	TypeSArray *tsa = (TypeSArray *)bt;
+	e->type = tsa->next;
+	bt = tsa->next->toBasetype();
+    }
+    return e;
+}
+
+int TypeTypedef::isZeroInit()
+{
+    if (sym->init)
+    {
+	if (sym->init->isVoidInitializer())
+	    return 1;		// initialize voids to 0
+	Expression *e = sym->init->toExpression();
+	if (e && e->isBool(FALSE))
+	    return 1;
+	return 0;		// assume not
+    }
+    if (sym->inuse)
+    {
+	sym->error("circular definition");
+	sym->basetype = Type::terror;
+    }
+    sym->inuse = 1;
+    int result = sym->basetype->isZeroInit();
+    sym->inuse = 0;
+    return result;
+}
+
+int TypeTypedef::hasPointers()
+{
+    return toBasetype()->hasPointers();
+}
+
+/***************************** TypeStruct *****************************/
+
+TypeStruct::TypeStruct(StructDeclaration *sym)
+	: Type(Tstruct)
+{
+    this->sym = sym;
+}
+
+char *TypeStruct::toChars()
+{
+    //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco);
+    if (mod)
+	return Type::toChars();
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+    if (ti && ti->toAlias() == sym)
+    {
+	return ti->toChars();
+    }
+    return sym->toChars();
+}
+
+Type *TypeStruct::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeStruct::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeStruct::semantic('%s')\n", sym->toChars());
+
+    /* Cannot do semantic for sym because scope chain may not
+     * be right.
+     */
+    //sym->semantic(sc);
+
+    return merge();
+}
+
+d_uns64 TypeStruct::size(Loc loc)
+{
+    return sym->size(loc);
+}
+
+unsigned TypeStruct::alignsize()
+{   unsigned sz;
+
+    sym->size(0);		// give error for forward references
+    sz = sym->alignsize;
+    if (sz > sym->structalign)
+	sz = sym->structalign;
+    return sz;
+}
+
+Dsymbol *TypeStruct::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    const char *name = sym->mangle();
+    //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name);
+    Type::toDecoBuffer(buf, flag);
+    buf->printf("%s", name);
+}
+
+void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+    if (ti && ti->toAlias() == sym)
+	buf->writestring(ti->toChars());
+    else
+	buf->writestring(sym->toChars());
+}
+
+Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   unsigned offset;
+
+    Expression *b;
+    VarDeclaration *v;
+    Dsymbol *s;
+    DotVarExp *de;
+    Declaration *d;
+
+#if LOGDOTEXP
+    printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (!sym->members)
+    {
+	error(e->loc, "struct %s is forward referenced", sym->toChars());
+	return new IntegerExp(e->loc, 0, Type::tint32);
+    }
+
+    /* If e.tupleof
+     */
+    if (ident == Id::tupleof)
+    {
+	/* Create a TupleExp out of the fields of the struct e:
+	 * (e.field0, e.field1, e.field2, ...)
+	 */
+	e = e->semantic(sc);	// do this before turning on noaccesscheck
+	Expressions *exps = new Expressions;
+	exps->reserve(sym->fields.dim);
+	for (size_t i = 0; i < sym->fields.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
+	    Expression *fe = new DotVarExp(e->loc, e, v);
+	    exps->push(fe);
+	}
+	e = new TupleExp(e->loc, exps);
+	sc = sc->push();
+	sc->noaccesscheck = 1;
+	e = e->semantic(sc);
+	sc->pop();
+	return e;
+    }
+
+    if (e->op == TOKdotexp)
+    {	DotExp *de = (DotExp *)e;
+
+	if (de->e1->op == TOKimport)
+	{
+	    assert(0);	// cannot find a case where this happens; leave
+			// assert in until we do
+	    ScopeExp *se = (ScopeExp *)de->e1;
+
+	    s = se->sds->search(e->loc, ident, 0);
+	    e = de->e1;
+	    goto L1;
+	}
+    }
+
+    s = sym->search(e->loc, ident, 0);
+L1:
+    if (!s)
+    {
+	if (ident != Id::__sizeof &&
+	    ident != Id::alignof &&
+	    ident != Id::init &&
+	    ident != Id::mangleof &&
+	    ident != Id::stringof &&
+	    ident != Id::offsetof)
+	{
+	    /* Look for overloaded opDot() to see if we should forward request
+	     * to it.
+	     */
+	    Dsymbol *fd = search_function(sym, Id::opDot);
+	    if (fd)
+	    {   /* Rewrite e.ident as:
+		 *	e.opId().ident
+		 */
+		e = build_overload(e->loc, sc, e, NULL, fd->ident);
+		e = new DotIdExp(e->loc, e, ident);
+		return e->semantic(sc);
+	    }
+	}
+	return Type::dotExp(sc, e, ident);
+    }
+    if (!s->isFuncDeclaration())	// because of overloading
+	s->checkDeprecated(e->loc, sc);
+    s = s->toAlias();
+
+    v = s->isVarDeclaration();
+    if (v && !v->isDataseg())
+    {
+	Expression *ei = v->getConstInitializer();
+	if (ei)
+	{   e = ei->copy();	// need to copy it if it's a StringExp
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    if (s->getType())
+    {
+	//return new DotTypeExp(e->loc, e, s);
+	return new TypeExp(e->loc, s->getType());
+    }
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+	assert(em->value);
+	return em->value->copy();
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {
+	Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+	de->type = e->type;
+	return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        e = new DotTemplateExp(e->loc, e, td);
+        e->semantic(sc);
+	return e;
+    }
+
+    TemplateInstance *ti = s->isTemplateInstance();
+    if (ti)
+    {	if (!ti->semanticdone)
+	    ti->semantic(sc);
+	s = ti->inst->toAlias();
+	if (!s->isTemplateInstance())
+	    goto L1;
+	Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+	de->type = e->type;
+	return de;
+    }
+
+    d = s->isDeclaration();
+#ifdef DEBUG
+    if (!d)
+	printf("d = %s '%s'\n", s->kind(), s->toChars());
+#endif
+    assert(d);
+
+    if (e->op == TOKtype)
+    {	FuncDeclaration *fd = sc->func;
+
+	if (d->needThis() && fd && fd->vthis)
+	{
+	    e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+	    e = e->semantic(sc);
+	    return e;
+	}
+	if (d->isTupleDeclaration())
+	{
+	    e = new TupleExp(e->loc, d->isTupleDeclaration());
+	    e = e->semantic(sc);
+	    return e;
+	}
+	return new VarExp(e->loc, d, 1);
+    }
+
+    if (d->isDataseg())
+    {
+	// (e, d)
+	VarExp *ve;
+
+	accessCheck(e->loc, sc, e, d);
+	ve = new VarExp(e->loc, d);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    if (v)
+    {
+	if (v->toParent() != sym)
+	    sym->error(e->loc, "'%s' is not a member", v->toChars());
+
+	// *(&e + offset)
+	accessCheck(e->loc, sc, e, d);
+
+// LDC we don't want dot exprs turned into pointer arithmetic. it complicates things for no apparent gain
+#ifndef IN_LLVM
+	b = new AddrExp(e->loc, e);
+	b->type = e->type->pointerTo();
+	b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
+	b->type = v->type->pointerTo();
+	b = new PtrExp(e->loc, b);
+	b->type = v->type;
+	if (e->type->isConst())
+	    b->type = b->type->constOf();
+	else if (e->type->isInvariant())
+	    b->type = b->type->invariantOf();
+	return b;
+#endif
+    }
+
+    de = new DotVarExp(e->loc, e, d);
+    return de->semantic(sc);
+}
+
+unsigned TypeStruct::memalign(unsigned salign)
+{
+    sym->size(0);		// give error for forward references
+    return sym->structalign;
+}
+
+Expression *TypeStruct::defaultInit(Loc loc)
+{   Symbol *s;
+    Declaration *d;
+
+#if LOGDEFAULTINIT
+    printf("TypeStruct::defaultInit() '%s'\n", toChars());
+#endif
+    s = sym->toInitializer();
+    d = new SymbolDeclaration(sym->loc, s, sym);
+    assert(d);
+    d->type = this;
+    return new VarExp(sym->loc, d);
+}
+
+int TypeStruct::isZeroInit()
+{
+    return sym->zeroInit;
+}
+
+int TypeStruct::checkBoolean()
+{
+    return FALSE;
+}
+
+int TypeStruct::isAssignable()
+{
+    /* If any of the fields are const or invariant,
+     * then one cannot assign this struct.
+     */
+    for (size_t i = 0; i < sym->fields.dim; i++)
+    {   VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
+	if (v->isConst() || v->isInvariant())
+	    return FALSE;
+    }
+    return TRUE;
+}
+
+int TypeStruct::hasPointers()
+{
+    StructDeclaration *s = sym;
+
+    sym->size(0);		// give error for forward references
+    for (size_t i = 0; i < s->fields.dim; i++)
+    {
+	Dsymbol *sm = (Dsymbol *)s->fields.data[i];
+	if (sm->hasPointers())
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+MATCH TypeStruct::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
+    if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
+    {	m = MATCHexact;		// exact match
+	if (mod != to->mod)
+	{
+	    if (to->mod == MODconst)
+		m = MATCHconst;
+	    else
+	    {	/* Check all the fields. If they can all be converted,
+		 * allow the conversion.
+		 */
+		for (int i = 0; i < sym->fields.dim; i++)
+		{   Dsymbol *s = (Dsymbol *)sym->fields.data[i];
+		    VarDeclaration *v = s->isVarDeclaration();
+		    assert(v && v->storage_class & STCfield);
+
+		    // 'from' type
+		    Type *tvf = v->type;
+		    if (mod == MODconst)
+			tvf = tvf->constOf();
+		    else if (mod == MODinvariant)
+			tvf = tvf->invariantOf();
+
+		    // 'to' type
+		    Type *tv = v->type;
+		    if (to->mod == 0)
+			tv = tv->mutableOf();
+		    else
+		    {	assert(to->mod == MODinvariant);
+			tv = tv->invariantOf();
+		    }
+
+		    //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv));
+		    if (tvf->implicitConvTo(tv) < MATCHconst)
+			return MATCHnomatch;
+		}
+		m = MATCHconst;
+	    }
+	}
+    }
+    else
+	m = MATCHnomatch;	// no match
+    return m;
+}
+
+Type *TypeStruct::toHeadMutable()
+{
+    return this;
+}
+
+MATCH TypeStruct::constConv(Type *to)
+{
+    if (equals(to))
+	return MATCHexact;
+    if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
+	to->mod == MODconst)
+	return MATCHconst;
+    return MATCHnomatch;
+}
+
+
+/***************************** TypeClass *****************************/
+
+TypeClass::TypeClass(ClassDeclaration *sym)
+	: Type(Tclass)
+{
+    this->sym = sym;
+}
+
+char *TypeClass::toChars()
+{
+    if (mod)
+	return Type::toChars();
+    return sym->toPrettyChars();
+}
+
+Type *TypeClass::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeClass::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeClass::semantic(%s)\n", sym->toChars());
+    if (sym->scope)
+	sym->semantic(sym->scope);
+    return merge();
+}
+
+d_uns64 TypeClass::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+Dsymbol *TypeClass::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+void TypeClass::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    const char *name = sym->mangle();
+    //printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name);
+    Type::toDecoBuffer(buf, flag);
+    buf->printf("%s", name);
+}
+
+void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    buf->writestring(sym->toChars());
+}
+
+Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   unsigned offset;
+
+    Expression *b;
+    VarDeclaration *v;
+    Dsymbol *s;
+
+#if LOGDOTEXP
+    printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    if (e->op == TOKdotexp)
+    {	DotExp *de = (DotExp *)e;
+
+	if (de->e1->op == TOKimport)
+	{
+	    ScopeExp *se = (ScopeExp *)de->e1;
+
+	    s = se->sds->search(e->loc, ident, 0);
+	    e = de->e1;
+	    goto L1;
+	}
+    }
+
+    if (ident == Id::tupleof)
+    {
+	/* Create a TupleExp
+	 */
+	e = e->semantic(sc);	// do this before turning on noaccesscheck
+	Expressions *exps = new Expressions;
+	exps->reserve(sym->fields.dim);
+	for (size_t i = 0; i < sym->fields.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
+	    Expression *fe = new DotVarExp(e->loc, e, v);
+	    exps->push(fe);
+	}
+	e = new TupleExp(e->loc, exps);
+	sc = sc->push();
+	sc->noaccesscheck = 1;
+	e = e->semantic(sc);
+	sc->pop();
+	return e;
+    }
+
+    s = sym->search(e->loc, ident, 0);
+L1:
+    if (!s)
+    {
+	// See if it's a base class
+	ClassDeclaration *cbase;
+	for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass)
+	{
+	    if (cbase->ident->equals(ident))
+	    {
+		e = new DotTypeExp(0, e, cbase);
+		return e;
+	    }
+	}
+
+	if (ident == Id::classinfo)
+	{
+	    assert(ClassDeclaration::classinfo);
+	    Type *t = ClassDeclaration::classinfo->type;
+	    if (e->op == TOKtype || e->op == TOKdottype)
+	    {
+		/* For type.classinfo, we know the classinfo
+		 * at compile time.
+		 */
+		if (!sym->vclassinfo)
+		    sym->vclassinfo = new ClassInfoDeclaration(sym);
+		e = new VarExp(e->loc, sym->vclassinfo);
+		e = e->addressOf(sc);
+		e->type = t;	// do this so we don't get redundant dereference
+	    }
+	    else
+	    {
+        /* For class objects, the classinfo reference is the first
+         * entry in the vtbl[]
+         */
+#if IN_LLVM
+
+        Type* ct;
+        if (sym->isInterfaceDeclaration()) {
+            ct = t->pointerTo()->pointerTo()->pointerTo();
+        }
+        else {
+            ct = t->pointerTo()->pointerTo();
+        }
+
+        e = e->castTo(sc, ct);
+        e = new PtrExp(e->loc, e);
+        e->type = ct->nextOf();
+        e = new PtrExp(e->loc, e);
+        e->type = ct->nextOf()->nextOf();
+
+        if (sym->isInterfaceDeclaration())
+        {
+            if (sym->isCOMinterface())
+            {   /* COM interface vtbl[]s are different in that the
+             * first entry is always pointer to QueryInterface().
+             * We can't get a .classinfo for it.
+             */
+            error(e->loc, "no .classinfo for COM interface objects");
+            }
+            /* For an interface, the first entry in the vtbl[]
+             * is actually a pointer to an instance of struct Interface.
+             * The first member of Interface is the .classinfo,
+             * so add an extra pointer indirection.
+             */
+            e = new PtrExp(e->loc, e);
+            e->type = ct->nextOf()->nextOf()->nextOf();
+        }
+        }
+
+#else
+
+		e = new PtrExp(e->loc, e);
+		e->type = t->pointerTo();
+		if (sym->isInterfaceDeclaration())
+		{
+		    if (sym->isCPPinterface())
+		    {	/* C++ interface vtbl[]s are different in that the
+			 * first entry is always pointer to the first virtual
+			 * function, not classinfo.
+			 * We can't get a .classinfo for it.
+			 */
+			error(e->loc, "no .classinfo for C++ interface objects");
+		    }
+		    /* For an interface, the first entry in the vtbl[]
+		     * is actually a pointer to an instance of struct Interface.
+		     * The first member of Interface is the .classinfo,
+		     * so add an extra pointer indirection.
+		     */
+		    e->type = e->type->pointerTo();
+		    e = new PtrExp(e->loc, e);
+		    e->type = t->pointerTo();
+		}
+		e = new PtrExp(e->loc, e, t);
+        }
+
+#endif // !LDC
+
+	    return e;
+	}
+
+	if (ident == Id::__vptr)
+	{   /* The pointer to the vtbl[]
+	     * *cast(invariant(void*)**)e
+	     */
+	    e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo());
+	    e = new PtrExp(e->loc, e);
+	    e = e->semantic(sc);
+	    return e;
+	}
+
+	if (ident == Id::__monitor)
+	{   /* The handle to the monitor (call it a void*)
+	     * *(cast(void**)e + 1)
+	     */
+	    e = e->castTo(sc, tvoidptr->pointerTo());
+	    e = new AddExp(e->loc, e, new IntegerExp(1));
+	    e = new PtrExp(e->loc, e);
+	    e = e->semantic(sc);
+	    return e;
+	}
+
+	if (ident == Id::typeinfo)
+	{
+	    if (!global.params.useDeprecated)
+		error(e->loc, ".typeinfo deprecated, use typeid(type)");
+	    return getTypeInfo(sc);
+	}
+	if (ident == Id::outer && sym->vthis)
+	{
+	    s = sym->vthis;
+	}
+	else
+	{
+
+	    if (ident != Id::__sizeof &&
+		ident != Id::alignof &&
+		ident != Id::init &&
+		ident != Id::mangleof &&
+		ident != Id::stringof &&
+		ident != Id::offsetof)
+	    {
+		/* Look for overloaded opDot() to see if we should forward request
+		 * to it.
+		 */
+		Dsymbol *fd = search_function(sym, Id::opDot);
+		if (fd)
+		{   /* Rewrite e.ident as:
+		     *	e.opId().ident
+		     */
+		    e = build_overload(e->loc, sc, e, NULL, fd->ident);
+		    e = new DotIdExp(e->loc, e, ident);
+		    return e->semantic(sc);
+		}
+	    }
+
+	    return Type::dotExp(sc, e, ident);
+	}
+    }
+    if (!s->isFuncDeclaration())	// because of overloading
+	s->checkDeprecated(e->loc, sc);
+    s = s->toAlias();
+    v = s->isVarDeclaration();
+    if (v && !v->isDataseg())
+    {	Expression *ei = v->getConstInitializer();
+
+	if (ei)
+	{   e = ei->copy();	// need to copy it if it's a StringExp
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    if (s->getType())
+    {
+//	if (e->op == TOKtype)
+	    return new TypeExp(e->loc, s->getType());
+//	return new DotTypeExp(e->loc, e, s);
+    }
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+	assert(em->value);
+	return em->value->copy();
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {
+	Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+	de->type = e->type;
+	return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        e = new DotTemplateExp(e->loc, e, td);
+        e->semantic(sc);
+	return e;
+    }
+
+    TemplateInstance *ti = s->isTemplateInstance();
+    if (ti)
+    {	if (!ti->semanticdone)
+	    ti->semantic(sc);
+	s = ti->inst->toAlias();
+	if (!s->isTemplateInstance())
+	    goto L1;
+	Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+	de->type = e->type;
+	return de;
+    }
+
+    Declaration *d = s->isDeclaration();
+    if (!d)
+    {
+	e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+	return new IntegerExp(e->loc, 1, Type::tint32);
+    }
+
+    if (e->op == TOKtype)
+    {
+	/* It's:
+	 *    Class.d
+	 */
+	if (d->needThis() && (hasThis(sc) || !d->isFuncDeclaration()))
+	{
+	    if (sc->func)
+	    {
+		ClassDeclaration *thiscd;
+		thiscd = sc->func->toParent()->isClassDeclaration();
+
+		if (thiscd)
+		{
+		    ClassDeclaration *cd = e->type->isClassHandle();
+
+		    if (cd == thiscd)
+		    {
+			e = new ThisExp(e->loc);
+			e = new DotTypeExp(e->loc, e, cd);
+			DotVarExp *de = new DotVarExp(e->loc, e, d);
+			e = de->semantic(sc);
+			return e;
+		    }
+		    else if ((!cd || !cd->isBaseOf(thiscd, NULL)) &&
+			     !d->isFuncDeclaration())
+			e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars());
+		}
+	    }
+
+	    /* Rewrite as:
+	     *	this.d
+	     */
+	    DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+	    e = de->semantic(sc);
+	    return e;
+	}
+	else if (d->isTupleDeclaration())
+	{
+	    e = new TupleExp(e->loc, d->isTupleDeclaration());
+	    e = e->semantic(sc);
+	    return e;
+	}
+	else
+	{
+	    VarExp *ve = new VarExp(e->loc, d, 1);
+	    return ve;
+	}
+    }
+
+    if (d->isDataseg())
+    {
+	// (e, d)
+	VarExp *ve;
+
+	accessCheck(e->loc, sc, e, d);
+	ve = new VarExp(e->loc, d);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    if (d->parent && d->toParent()->isModule())
+    {
+	// (e, d)
+
+	VarExp *ve = new VarExp(e->loc, d, 1);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    DotVarExp *de = new DotVarExp(e->loc, e, d);
+    return de->semantic(sc);
+}
+
+ClassDeclaration *TypeClass::isClassHandle()
+{
+    return sym;
+}
+
+int TypeClass::isauto()
+{
+    return sym->isauto;
+}
+
+int TypeClass::isBaseOf(Type *t, int *poffset)
+{
+    if (t->ty == Tclass)
+    {   ClassDeclaration *cd;
+
+	cd   = ((TypeClass *)t)->sym;
+	if (sym->isBaseOf(cd, poffset))
+	    return 1;
+    }
+    return 0;
+}
+
+MATCH TypeClass::implicitConvTo(Type *to)
+{
+    //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
+    MATCH m = constConv(to);
+    if (m != MATCHnomatch)
+	return m;
+
+    ClassDeclaration *cdto = to->isClassHandle();
+    if (cdto && cdto->isBaseOf(sym, NULL))
+    {	//printf("'to' is base\n");
+	return MATCHconvert;
+    }
+
+    if (global.params.Dversion == 1)
+    {
+	// Allow conversion to (void *)
+	if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid)
+	    return MATCHconvert;
+    }
+
+    return MATCHnomatch;
+}
+
+MATCH TypeClass::constConv(Type *to)
+{
+    if (equals(to))
+	return MATCHexact;
+    if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
+	to->mod == MODconst)
+	return MATCHconst;
+    return MATCHnomatch;
+}
+
+Type *TypeClass::toHeadMutable()
+{
+    return this;
+}
+
+Expression *TypeClass::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeClass::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(loc);
+    e->type = this;
+    return e;
+}
+
+int TypeClass::isZeroInit()
+{
+    return 1;
+}
+
+int TypeClass::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeClass::hasPointers()
+{
+    return TRUE;
+}
+
+/***************************** TypeTuple *****************************/
+
+TypeTuple::TypeTuple(Arguments *arguments)
+    : Type(Ttuple)
+{
+    //printf("TypeTuple(this = %p)\n", this);
+    this->arguments = arguments;
+    //printf("TypeTuple() %s\n", toChars());
+#ifdef DEBUG
+    if (arguments)
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{
+	    Argument *arg = (Argument *)arguments->data[i];
+	    assert(arg && arg->type);
+	}
+    }
+#endif
+}
+
+/****************
+ * Form TypeTuple from the types of the expressions.
+ * Assume exps[] is already tuple expanded.
+ */
+
+TypeTuple::TypeTuple(Expressions *exps)
+    : Type(Ttuple)
+{
+    Arguments *arguments = new Arguments;
+    if (exps)
+    {
+	arguments->setDim(exps->dim);
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *e = (Expression *)exps->data[i];
+	    if (e->type->ty == Ttuple)
+		e->error("cannot form tuple of tuples");
+	    Argument *arg = new Argument(STCundefined, e->type, NULL, NULL);
+	    arguments->data[i] = (void *)arg;
+	}
+    }
+    this->arguments = arguments;
+}
+
+Type *TypeTuple::syntaxCopy()
+{
+    Arguments *args = Argument::arraySyntaxCopy(arguments);
+    Type *t = new TypeTuple(args);
+    t->mod = mod;
+    return t;
+}
+
+Type *TypeTuple::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTuple::semantic(this = %p)\n", this);
+    //printf("TypeTuple::semantic() %s\n", toChars());
+    if (!deco)
+	deco = merge()->deco;
+
+    /* Don't return merge(), because a tuple with one type has the
+     * same deco as that type.
+     */
+    return this;
+}
+
+int TypeTuple::equals(Object *o)
+{   Type *t;
+
+    t = (Type *)o;
+    //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
+    if (this == t)
+    {
+	return 1;
+    }
+    if (t->ty == Ttuple)
+    {	TypeTuple *tt = (TypeTuple *)t;
+
+	if (arguments->dim == tt->arguments->dim)
+	{
+	    for (size_t i = 0; i < tt->arguments->dim; i++)
+	    {   Argument *arg1 = (Argument *)arguments->data[i];
+		Argument *arg2 = (Argument *)tt->arguments->data[i];
+
+		if (!arg1->type->equals(arg2->type))
+		    return 0;
+	    }
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+Type *TypeTuple::reliesOnTident()
+{
+    if (arguments)
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{
+	    Argument *arg = (Argument *)arguments->data[i];
+	    Type *t = arg->type->reliesOnTident();
+	    if (t)
+		return t;
+	}
+    }
+    return NULL;
+}
+
+#if 0
+Type *TypeTuple::makeConst()
+{
+    //printf("TypeTuple::makeConst() %s\n", toChars());
+    if (cto)
+	return cto;
+    TypeTuple *t = (TypeTuple *)Type::makeConst();
+    t->arguments = new Arguments();
+    t->arguments->setDim(arguments->dim);
+    for (size_t i = 0; i < arguments->dim; i++)
+    {   Argument *arg = (Argument *)arguments->data[i];
+	Argument *narg = new Argument(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg);
+	t->arguments->data[i] = (Argument *)narg;
+    }
+    return t;
+}
+#endif
+
+void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    Argument::argsToCBuffer(buf, hgs, arguments, 0);
+}
+
+void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag)
+{
+    //printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars());
+    Type::toDecoBuffer(buf, flag);
+    OutBuffer buf2;
+    Argument::argsToDecoBuffer(&buf2, arguments);
+    unsigned len = buf2.offset;
+    buf->printf("%d%.*s", len, len, (char *)buf2.extractData());
+}
+
+Expression *TypeTuple::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+#if LOGDOTEXP
+    printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
+    }
+    else
+    {
+	error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
+	e = new IntegerExp(loc, 1, Type::tint32);
+    }
+    return e;
+}
+
+/***************************** TypeSlice *****************************/
+
+/* This is so we can slice a TypeTuple */
+
+TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
+    : TypeNext(Tslice, next)
+{
+    //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
+    this->lwr = lwr;
+    this->upr = upr;
+}
+
+Type *TypeSlice::syntaxCopy()
+{
+    Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
+    t->mod = mod;
+    return t;
+}
+
+Type *TypeSlice::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSlice::semantic() %s\n", toChars());
+    next = next->semantic(loc, sc);
+    if (mod == MODconst && !next->isInvariant())
+	next = next->constOf();
+    else if (mod == MODinvariant)
+	next = next->invariantOf();
+    //printf("next: %s\n", next->toChars());
+
+    Type *tbn = next->toBasetype();
+    if (tbn->ty != Ttuple)
+    {	error(loc, "can only slice tuple types, not %s", tbn->toChars());
+	return Type::terror;
+    }
+    TypeTuple *tt = (TypeTuple *)tbn;
+
+    lwr = semanticLength(sc, tbn, lwr);
+    lwr = lwr->optimize(WANTvalue);
+    uinteger_t i1 = lwr->toUInteger();
+
+    upr = semanticLength(sc, tbn, upr);
+    upr = upr->optimize(WANTvalue);
+    uinteger_t i2 = upr->toUInteger();
+
+    if (!(i1 <= i2 && i2 <= tt->arguments->dim))
+    {	error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
+	return Type::terror;
+    }
+
+    Arguments *args = new Arguments;
+    args->reserve(i2 - i1);
+    for (size_t i = i1; i < i2; i++)
+    {	Argument *arg = (Argument *)tt->arguments->data[i];
+	args->push(arg);
+    }
+
+    return new TypeTuple(args);
+}
+
+void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    next->resolve(loc, sc, pe, pt, ps);
+    if (*pe)
+    {	// It's really a slice expression
+	Expression *e;
+	e = new SliceExp(loc, *pe, lwr, upr);
+	*pe = e;
+    }
+    else if (*ps)
+    {	Dsymbol *s = *ps;
+	TupleDeclaration *td = s->isTupleDeclaration();
+	if (td)
+	{
+	    /* It's a slice of a TupleDeclaration
+	     */
+	    ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+	    sym->parent = sc->scopesym;
+	    sc = sc->push(sym);
+
+	    lwr = lwr->semantic(sc);
+	    lwr = lwr->optimize(WANTvalue);
+	    uinteger_t i1 = lwr->toUInteger();
+
+	    upr = upr->semantic(sc);
+	    upr = upr->optimize(WANTvalue);
+	    uinteger_t i2 = upr->toUInteger();
+
+	    sc = sc->pop();
+
+	    if (!(i1 <= i2 && i2 <= td->objects->dim))
+	    {   error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim);
+		goto Ldefault;
+	    }
+
+	    if (i1 == 0 && i2 == td->objects->dim)
+	    {
+		*ps = td;
+		return;
+	    }
+
+	    /* Create a new TupleDeclaration which
+	     * is a slice [i1..i2] out of the old one.
+	     */
+	    Objects *objects = new Objects;
+	    objects->setDim(i2 - i1);
+	    for (size_t i = 0; i < objects->dim; i++)
+	    {
+		objects->data[i] = td->objects->data[(size_t)i1 + i];
+	    }
+
+	    TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+	    *ps = tds;
+	}
+	else
+	    goto Ldefault;
+    }
+    else
+    {
+     Ldefault:
+	Type::resolve(loc, sc, pe, pt, ps);
+    }
+}
+
+void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
+{
+    if (mod != this->mod)
+    {	toCBuffer3(buf, hgs, mod);
+	return;
+    }
+    next->toCBuffer2(buf, hgs, this->mod);
+
+    buf->printf("[%s .. ", lwr->toChars());
+    buf->printf("%s]", upr->toChars());
+}
+
+/***************************** Argument *****************************/
+
+Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+    this->type = type;
+    this->ident = ident;
+    this->storageClass = storageClass;
+    this->defaultArg = defaultArg;
+    this->llvmAttrs = 0;
+}
+
+Argument *Argument::syntaxCopy()
+{
+    Argument *a = new Argument(storageClass,
+		type ? type->syntaxCopy() : NULL,
+		ident,
+		defaultArg ? defaultArg->syntaxCopy() : NULL);
+    a->llvmAttrs = llvmAttrs;
+    return a;
+}
+
+Arguments *Argument::arraySyntaxCopy(Arguments *args)
+{   Arguments *a = NULL;
+
+    if (args)
+    {
+	a = new Arguments();
+	a->setDim(args->dim);
+	for (size_t i = 0; i < a->dim; i++)
+	{   Argument *arg = (Argument *)args->data[i];
+
+	    arg = arg->syntaxCopy();
+	    a->data[i] = (void *)arg;
+	}
+    }
+    return a;
+}
+
+char *Argument::argsTypesToChars(Arguments *args, int varargs)
+{
+    OutBuffer *buf = new OutBuffer();
+
+#if 1
+    HdrGenState hgs;
+    argsToCBuffer(buf, &hgs, args, varargs);
+#else
+    buf->writeByte('(');
+    if (args)
+    {	OutBuffer argbuf;
+	HdrGenState hgs;
+
+	for (int i = 0; i < args->dim; i++)
+	{   if (i)
+		buf->writeByte(',');
+	    Argument *arg = (Argument *)args->data[i];
+	    argbuf.reset();
+	    arg->type->toCBuffer2(&argbuf, &hgs, 0);
+	    buf->write(&argbuf);
+	}
+	if (varargs)
+	{
+	    if (i && varargs == 1)
+		buf->writeByte(',');
+	    buf->writestring("...");
+	}
+    }
+    buf->writeByte(')');
+#endif
+    return buf->toChars();
+}
+
+void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs)
+{
+    buf->writeByte('(');
+    if (arguments)
+    {	int i;
+	OutBuffer argbuf;
+
+	for (i = 0; i < arguments->dim; i++)
+	{
+	    if (i)
+		buf->writestring(", ");
+	    Argument *arg = (Argument *)arguments->data[i];
+
+	    if (arg->storageClass & STCout)
+		buf->writestring("out ");
+	    else if (arg->storageClass & STCref)
+		buf->writestring((global.params.Dversion == 1)
+			? (char *)"inout " : (char *)"ref ");
+	    else if (arg->storageClass & STCin)
+		buf->writestring("in ");
+	    else if (arg->storageClass & STClazy)
+		buf->writestring("lazy ");
+	    else if (arg->storageClass & STCalias)
+		buf->writestring("alias ");
+	    else if (arg->storageClass & STCauto)
+		buf->writestring("auto ");
+
+	    if (arg->storageClass & STCconst)
+		buf->writestring("const ");
+	    if (arg->storageClass & STCinvariant)
+		buf->writestring("invariant ");
+
+	    argbuf.reset();
+	    if (arg->storageClass & STCalias)
+	    {	if (arg->ident)
+		    argbuf.writestring(arg->ident->toChars());
+	    }
+	    else
+		arg->type->toCBuffer(&argbuf, arg->ident, hgs);
+	    if (arg->defaultArg)
+	    {
+		argbuf.writestring(" = ");
+		arg->defaultArg->toCBuffer(&argbuf, hgs);
+	    }
+	    buf->write(&argbuf);
+	}
+	if (varargs)
+	{
+	    if (i && varargs == 1)
+		buf->writeByte(',');
+	    buf->writestring("...");
+	}
+    }
+    buf->writeByte(')');
+}
+
+
+void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments)
+{
+    //printf("Argument::argsToDecoBuffer()\n");
+
+    // Write argument types
+    if (arguments)
+    {
+	size_t dim = Argument::dim(arguments);
+	for (size_t i = 0; i < dim; i++)
+	{
+	    Argument *arg = Argument::getNth(arguments, i);
+	    arg->toDecoBuffer(buf);
+	}
+    }
+}
+
+
+/****************************************
+ * Determine if parameter list is really a template parameter list
+ * (i.e. it has auto or alias parameters)
+ */
+
+int Argument::isTPL(Arguments *arguments)
+{
+    //printf("Argument::isTPL()\n");
+
+    if (arguments)
+    {
+	size_t dim = Argument::dim(arguments);
+	for (size_t i = 0; i < dim; i++)
+	{
+	    Argument *arg = Argument::getNth(arguments, i);
+	    if (arg->storageClass & (STCalias | STCauto | STCstatic))
+		return 1;
+	}
+    }
+    return 0;
+}
+
+/****************************************************
+ * Determine if parameter is a lazy array of delegates.
+ * If so, return the return type of those delegates.
+ * If not, return NULL.
+ */
+
+Type *Argument::isLazyArray()
+{
+//    if (inout == Lazy)
+    {
+	Type *tb = type->toBasetype();
+	if (tb->ty == Tsarray || tb->ty == Tarray)
+	{
+	    Type *tel = ((TypeArray *)tb)->next->toBasetype();
+	    if (tel->ty == Tdelegate)
+	    {
+		TypeDelegate *td = (TypeDelegate *)tel;
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
+		{
+		    return tf->next;	// return type of delegate
+		}
+	    }
+	}
+    }
+    return NULL;
+}
+
+void Argument::toDecoBuffer(OutBuffer *buf)
+{
+    switch (storageClass & (STCin | STCout | STCref | STClazy))
+    {   case 0:
+	case STCin:
+	    break;
+	case STCout:
+	    buf->writeByte('J');
+	    break;
+	case STCref:
+	    buf->writeByte('K');
+	    break;
+	case STClazy:
+	    buf->writeByte('L');
+	    break;
+	default:
+#ifdef DEBUG
+	    halt();
+#endif
+	    assert(0);
+    }
+#if 0
+    int mod = 0x100;
+    if (type->toBasetype()->ty == Tclass)
+	mod = 0;
+    type->toDecoBuffer(buf, mod);
+#else
+    //type->toHeadMutable()->toDecoBuffer(buf, 0);
+    type->toDecoBuffer(buf, 0);
+#endif
+}
+
+/***************************************
+ * Determine number of arguments, folding in tuples.
+ */
+
+size_t Argument::dim(Arguments *args)
+{
+    size_t n = 0;
+    if (args)
+    {
+	for (size_t i = 0; i < args->dim; i++)
+	{   Argument *arg = (Argument *)args->data[i];
+	    Type *t = arg->type->toBasetype();
+
+	    if (t->ty == Ttuple)
+	    {   TypeTuple *tu = (TypeTuple *)t;
+		n += dim(tu->arguments);
+	    }
+	    else
+		n++;
+	}
+    }
+    return n;
+}
+
+/***************************************
+ * Get nth Argument, folding in tuples.
+ * Returns:
+ *	Argument*	nth Argument
+ *	NULL		not found, *pn gets incremented by the number
+ *			of Arguments
+ */
+
+Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn)
+{
+    if (!args)
+	return NULL;
+
+    size_t n = 0;
+    for (size_t i = 0; i < args->dim; i++)
+    {   Argument *arg = (Argument *)args->data[i];
+	Type *t = arg->type->toBasetype();
+
+	if (t->ty == Ttuple)
+	{   TypeTuple *tu = (TypeTuple *)t;
+	    arg = getNth(tu->arguments, nth - n, &n);
+	    if (arg)
+		return arg;
+	}
+	else if (n == nth)
+	    return arg;
+	else
+	    n++;
+    }
+
+    if (pn)
+	*pn += n;
+    return NULL;
+}