diff dmd2/template.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 356e65836fb5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd2/template.c	Tue Nov 11 01:38:48 2008 +0100
@@ -0,0 +1,4615 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2008 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Handle template implementation
+
+#include <stdio.h>
+#include <assert.h>
+
+#if !IN_LLVM
+#if _WIN32
+#include <windows.h>
+long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
+#endif
+#endif
+
+#include "root.h"
+#include "mem.h"
+#include "stringtable.h"
+#include "mars.h"
+#include "identifier.h"
+#include "mtype.h"
+#include "template.h"
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "module.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "dsymbol.h"
+#include "hdrgen.h"
+
+#define LOG	0
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+
+Expression *isExpression(Object *o)
+{
+    //return dynamic_cast<Expression *>(o);
+    if (!o || o->dyncast() != DYNCAST_EXPRESSION)
+	return NULL;
+    return (Expression *)o;
+}
+
+Dsymbol *isDsymbol(Object *o)
+{
+    //return dynamic_cast<Dsymbol *>(o);
+    if (!o || o->dyncast() != DYNCAST_DSYMBOL)
+	return NULL;
+    return (Dsymbol *)o;
+}
+
+Type *isType(Object *o)
+{
+    //return dynamic_cast<Type *>(o);
+    if (!o || o->dyncast() != DYNCAST_TYPE)
+	return NULL;
+    return (Type *)o;
+}
+
+Tuple *isTuple(Object *o)
+{
+    //return dynamic_cast<Tuple *>(o);
+    if (!o || o->dyncast() != DYNCAST_TUPLE)
+	return NULL;
+    return (Tuple *)o;
+}
+
+
+/***********************
+ * Try to get arg as a type.
+ */
+
+Type *getType(Object *o)
+{
+    Type *t = isType(o);
+    if (!t)
+    {   Expression *e = isExpression(o);
+	if (e)
+	    t = e->type;
+    }
+    return t;
+}
+
+Dsymbol *getDsymbol(Object *oarg)
+{
+    Dsymbol *sa;
+    Expression *ea = isExpression(oarg);
+    if (ea)
+    {   // Try to convert Expression to symbol
+	if (ea->op == TOKvar)
+	    sa = ((VarExp *)ea)->var;
+	else if (ea->op == TOKfunction)
+	    sa = ((FuncExp *)ea)->fd;
+	else
+	    sa = NULL;
+    }
+    else
+    {   // Try to convert Type to symbol
+	Type *ta = isType(oarg);
+	if (ta)
+	    sa = ta->toDsymbol(NULL);
+	else
+	    sa = isDsymbol(oarg);	// if already a symbol
+    }
+    return sa;
+}
+
+/******************************
+ * If o1 matches o2, return 1.
+ * Else, return 0.
+ */
+
+int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc)
+{
+    Type *t1 = isType(o1);
+    Type *t2 = isType(o2);
+    Expression *e1 = isExpression(o1);
+    Expression *e2 = isExpression(o2);
+    Dsymbol *s1 = isDsymbol(o1);
+    Dsymbol *s2 = isDsymbol(o2);
+    Tuple *v1 = isTuple(o1);
+    Tuple *v2 = isTuple(o2);
+
+    //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2);
+
+    /* A proper implementation of the various equals() overrides
+     * should make it possible to just do o1->equals(o2), but
+     * we'll do that another day.
+     */
+
+    if (t1)
+    {
+	/* if t1 is an instance of ti, then give error
+	 * about recursive expansions.
+	 */
+	Dsymbol *s = t1->toDsymbol(sc);
+	if (s && s->parent)
+	{   TemplateInstance *ti1 = s->parent->isTemplateInstance();
+	    if (ti1 && ti1->tempdecl == tempdecl)
+	    {
+		for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing)
+		{
+		    if (sc1->scopesym == ti1)
+		    {
+			error("recursive template expansion for template argument %s", t1->toChars());
+			return 1;	// fake a match
+		    }
+		}
+	    }
+	}
+
+	if (!t2 || !t1->equals(t2))
+	    goto Lnomatch;
+    }
+    else if (e1)
+    {
+#if 0
+	if (e1 && e2)
+	{
+	    printf("match %d\n", e1->equals(e2));
+	    e1->print();
+	    e2->print();
+	    e1->type->print();
+	    e2->type->print();
+	}
+#endif
+	if (!e2)
+	    goto Lnomatch;
+	if (!e1->equals(e2))
+	    goto Lnomatch;
+    }
+    else if (s1)
+    {
+	//printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars());
+	if (!s2 || !s1->equals(s2) || s1->parent != s2->parent)
+	{
+	    goto Lnomatch;
+	}
+	VarDeclaration *v1 = s1->isVarDeclaration();
+	VarDeclaration *v2 = s2->isVarDeclaration();
+	if (v1 && v2 && v1->storage_class & v2->storage_class & STCmanifest)
+	{   ExpInitializer *ei1 = v1->init->isExpInitializer();
+	    ExpInitializer *ei2 = v2->init->isExpInitializer();
+	    if (ei1 && ei2 && !ei1->exp->equals(ei2->exp))
+		goto Lnomatch;
+	}
+    }
+    else if (v1)
+    {
+	if (!v2)
+	    goto Lnomatch;
+	if (v1->objects.dim != v2->objects.dim)
+	    goto Lnomatch;
+	for (size_t i = 0; i < v1->objects.dim; i++)
+	{
+	    if (!match((Object *)v1->objects.data[i],
+		       (Object *)v2->objects.data[i],
+		       tempdecl, sc))
+		goto Lnomatch;
+	}
+    }
+    //printf("match\n");
+    return 1;	// match
+Lnomatch:
+    //printf("nomatch\n");
+    return 0;	// nomatch;
+}
+
+/****************************************
+ */
+
+void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg)
+{
+    //printf("ObjectToCBuffer()\n");
+    Type *t = isType(oarg);
+    Expression *e = isExpression(oarg);
+    Dsymbol *s = isDsymbol(oarg);
+    Tuple *v = isTuple(oarg);
+    if (t)
+    {	//printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
+	t->toCBuffer(buf, NULL, hgs);
+    }
+    else if (e)
+	e->toCBuffer(buf, hgs);
+    else if (s)
+    {
+	char *p = s->ident ? s->ident->toChars() : s->toChars();
+	buf->writestring(p);
+    }
+    else if (v)
+    {
+	Objects *args = &v->objects;
+	for (size_t i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *o = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, o);
+	}
+    }
+    else if (!oarg)
+    {
+	buf->writestring("NULL");
+    }
+    else
+    {
+#ifdef DEBUG
+	printf("bad Object = %p\n", oarg);
+#endif
+	assert(0);
+    }
+}
+
+Object *objectSyntaxCopy(Object *o)
+{
+    if (!o)
+	return NULL;
+    Type *t = isType(o);
+    if (t)
+	return t->syntaxCopy();
+    Expression *e = isExpression(o);
+    if (e)
+	return e->syntaxCopy();
+    return o;
+}
+
+
+/* ======================== TemplateDeclaration ============================= */
+
+TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
+	TemplateParameters *parameters, Expression *constraint, Array *decldefs)
+    : ScopeDsymbol(id)
+{
+#if LOG
+    printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars());
+#endif
+#if 0
+    if (parameters)
+	for (int i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    //printf("\tparameter[%d] = %p\n", i, tp);
+	    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+	    if (ttp)
+	    {
+		printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+	    }
+	}
+#endif
+    this->loc = loc;
+    this->parameters = parameters;
+    this->origParameters = parameters;
+    this->constraint = constraint;
+    this->members = decldefs;
+    this->overnext = NULL;
+    this->overroot = NULL;
+    this->scope = NULL;
+    this->onemember = NULL;
+}
+
+Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
+{
+    //printf("TemplateDeclaration::syntaxCopy()\n");
+    TemplateDeclaration *td;
+    TemplateParameters *p;
+    Array *d;
+
+    p = NULL;
+    if (parameters)
+    {
+	p = new TemplateParameters();
+	p->setDim(parameters->dim);
+	for (int i = 0; i < p->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    p->data[i] = (void *)tp->syntaxCopy();
+	}
+    }
+    Expression *e = NULL;
+    if (constraint)
+	e = constraint->syntaxCopy();
+    d = Dsymbol::arraySyntaxCopy(members);
+    td = new TemplateDeclaration(loc, ident, p, e, d);
+    
+    // LDC
+    td->intrinsicName = intrinsicName;
+    
+    return td;
+}
+
+void TemplateDeclaration::semantic(Scope *sc)
+{
+#if LOG
+    printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars());
+#endif
+    if (scope)
+	return;		// semantic() already run
+
+    if (sc->func)
+    {
+//	error("cannot declare template at function scope %s", sc->func->toChars());
+    }
+
+    if (/*global.params.useArrayBounds &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleArray();
+    }
+
+    if (/*global.params.useAssert &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleAssert();
+    }
+
+    /* Remember Scope for later instantiations, but make
+     * a copy since attributes can change.
+     */
+    this->scope = new Scope(*sc);
+    this->scope->setNoFree();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = sc->parent;
+    Scope *paramscope = sc->push(paramsym);
+    paramscope->parameterSpecialization = 1;
+
+    if (global.params.doDocComments)
+    {
+	origParameters = new TemplateParameters();
+	origParameters->setDim(parameters->dim);
+	for (int i = 0; i < parameters->dim; i++)
+	{
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    origParameters->data[i] = (void *)tp->syntaxCopy();
+	}
+    }
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->declareParameter(paramscope);
+    }
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->semantic(paramscope);
+	if (i + 1 != parameters->dim && tp->isTemplateTupleParameter())
+	    error("template tuple parameter must be last one");
+    }
+
+    paramscope->pop();
+
+    if (members)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s))
+	{
+	    if (s && s->ident && s->ident->equals(ident))
+	    {
+		onemember = s;
+		s->parent = this;
+	    }
+	}
+    }
+
+    /* BUG: should check:
+     *	o no virtual functions or non-static data members of classes
+     */
+}
+
+const char *TemplateDeclaration::kind()
+{
+    return (onemember && onemember->isAggregateDeclaration())
+		? onemember->kind()
+		: (char *)"template";
+}
+
+/**********************************
+ * Overload existing TemplateDeclaration 'this' with the new one 's'.
+ * Return !=0 if successful; i.e. no conflict.
+ */
+
+int TemplateDeclaration::overloadInsert(Dsymbol *s)
+{
+    TemplateDeclaration **pf;
+    TemplateDeclaration *f;
+
+#if LOG
+    printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars());
+#endif
+    f = s->isTemplateDeclaration();
+    if (!f)
+	return FALSE;
+    TemplateDeclaration *pthis = this;
+    for (pf = &pthis; *pf; pf = &(*pf)->overnext)
+    {
+#if 0
+	// Conflict if TemplateParameter's match
+	// Will get caught anyway later with TemplateInstance, but
+	// should check it now.
+	TemplateDeclaration *f2 = *pf;
+
+	if (f->parameters->dim != f2->parameters->dim)
+	    goto Lcontinue;
+
+	for (int i = 0; i < f->parameters->dim; i++)
+	{   TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i];
+	    TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i];
+
+	    if (!p1->overloadMatch(p2))
+		goto Lcontinue;
+	}
+
+#if LOG
+	printf("\tfalse: conflict\n");
+#endif
+	return FALSE;
+
+     Lcontinue:
+	;
+#endif
+    }
+
+    f->overroot = this;
+    *pf = f;
+#if LOG
+    printf("\ttrue: no conflict\n");
+#endif
+    return TRUE;
+}
+
+/***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Input:
+ *	flag	1: don't do semantic() because of dummy types
+ *		2: don't change types in matchArg()
+ * Output:
+ *	dedtypes	deduced arguments
+ * Return match level.
+ */
+
+MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti,
+	Objects *dedtypes, int flag)
+{   MATCH m;
+    int dedtypes_dim = dedtypes->dim;
+
+#define LOGM 0
+#if LOGM
+    printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag);
+#endif
+
+#if 0
+    printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim);
+    if (ti->tiargs->dim)
+	printf("ti->tiargs->dim = %d, [0] = %p\n",
+	    ti->tiargs->dim,
+	    ti->tiargs->data[0]);
+#endif
+    dedtypes->zero();
+
+    int parameters_dim = parameters->dim;
+    int variadic = isVariadic() != NULL;
+
+    // If more arguments than parameters, no match
+    if (ti->tiargs->dim > parameters_dim && !variadic)
+    {
+#if LOGM
+	printf(" no match: more arguments than parameters\n");
+#endif
+	return MATCHnomatch;
+    }
+
+    assert(dedtypes_dim == parameters_dim);
+    assert(dedtypes_dim >= ti->tiargs->dim || variadic);
+
+    // Set up scope for parameters
+    assert((size_t)scope > 0x10000);
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    // Attempt type deduction
+    m = MATCHexact;
+    for (int i = 0; i < dedtypes_dim; i++)
+    {	MATCH m2;
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	Declaration *sparam;
+
+	//printf("\targument [%d]\n", i);
+#if LOGM
+	//printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
+	TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+	if (ttp)
+	    printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+#endif
+
+#if DMDV1
+	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+#else
+	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0);
+
+#endif
+	//printf("\tm2 = %d\n", m2);
+
+	if (m2 == MATCHnomatch)
+	{
+#if 0
+	    printf("\tmatchArg() for parameter %i failed\n", i);
+#endif
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+
+	if (!flag)
+	    sparam->semantic(paramscope);
+	if (!paramscope->insert(sparam))
+	    goto Lnomatch;
+    }
+
+    if (!flag)
+    {
+	/* Any parameter left without a type gets the type of
+	 * its corresponding arg
+	 */
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    if (!dedtypes->data[i])
+	    {   assert(i < ti->tiargs->dim);
+		dedtypes->data[i] = ti->tiargs->data[i];
+	    }
+	}
+    }
+
+    if (m && constraint && !(flag & 1))
+    {	/* Check to see if constraint is satisfied.
+	 */
+	Expression *e = constraint->syntaxCopy();
+	paramscope->flags |= SCOPEstaticif;
+	e = e->semantic(paramscope);
+	e = e->optimize(WANTvalue | WANTinterpret);
+        if (e->isBool(TRUE))
+            ;
+        else if (e->isBool(FALSE))
+            goto Lnomatch;
+        else
+        {
+            e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars());
+        }
+    }
+
+#if LOGM
+    // Print out the results
+    printf("--------------------------\n");
+    printf("template %s\n", toChars());
+    printf("instance %s\n", ti->toChars());
+    if (m)
+    {
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    Object *oarg;
+
+	    printf(" [%d]", i);
+
+	    if (i < ti->tiargs->dim)
+		oarg = (Object *)ti->tiargs->data[i];
+	    else
+		oarg = NULL;
+	    tp->print(oarg, (Object *)dedtypes->data[i]);
+	}
+    }
+    else
+	goto Lnomatch;
+#endif
+
+#if LOGM
+    printf(" match = %d\n", m);
+#endif
+    goto Lret;
+
+Lnomatch:
+#if LOGM
+    printf(" no match\n");
+#endif
+    m = MATCHnomatch;
+
+Lret:
+    paramscope->pop();
+#if LOGM
+    printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
+#endif
+    return m;
+}
+
+/********************************************
+ * Determine partial specialization order of 'this' vs td2.
+ * Returns:
+ *	match	this is at least as specialized as td2
+ *	0	td2 is more specialized than this
+ */
+
+MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2)
+{
+    /* This works by taking the template parameters to this template
+     * declaration and feeding them to td2 as if it were a template
+     * instance.
+     * If it works, then this template is at least as specialized
+     * as td2.
+     */
+
+    TemplateInstance ti(0, ident);	// create dummy template instance
+    Objects dedtypes;
+
+#define LOG_LEASTAS	0
+
+#if LOG_LEASTAS
+    printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars());
+#endif
+
+    // Set type arguments to dummy template instance to be types
+    // generated from the parameters to this template declaration
+    ti.tiargs = new Objects();
+    ti.tiargs->setDim(parameters->dim);
+    for (int i = 0; i < ti.tiargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	void *p = tp->dummyArg();
+	if (p)
+	    ti.tiargs->data[i] = p;
+	else
+	    ti.tiargs->setDim(i);
+    }
+
+    // Temporary Array to hold deduced types
+    //dedtypes.setDim(parameters->dim);
+    dedtypes.setDim(td2->parameters->dim);
+
+    // Attempt a type deduction
+    MATCH m = td2->matchWithInstance(&ti, &dedtypes, 1);
+    if (m)
+    {
+	/* A non-variadic template is more specialized than a
+	 * variadic one.
+	 */
+	if (isVariadic() && !td2->isVariadic())
+	    goto L1;
+
+#if LOG_LEASTAS
+	printf("  matches %d, so is least as specialized\n", m);
+#endif
+	return m;
+    }
+  L1:
+#if LOG_LEASTAS
+    printf("  doesn't match, so is not as specialized\n");
+#endif
+    return MATCHnomatch;
+}
+
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ *	loc		instantiation location
+ *	targsi		Expression/Type initial list of template arguments
+ *	ethis		'this' argument if !NULL
+ *	fargs		arguments to function
+ * Output:
+ *	dedargs		Expression/Type deduced template arguments
+ * Returns:
+ *	match level
+ */
+
+MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi,
+	Expression *ethis, Expressions *fargs,
+	Objects *dedargs)
+{
+    size_t i;
+    size_t nfparams;
+    size_t nfargs;
+    size_t nargsi;		// array size of targsi
+    int fptupindex = -1;
+    int tuple_dim = 0;
+    MATCH match = MATCHexact;
+    FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration();
+    TypeFunction *fdtype;		// type of fd
+    TemplateTupleParameter *tp;
+    Objects dedtypes;	// for T:T*, the dedargs is the T*, dedtypes is the T
+
+#if 0
+    printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
+    for (i = 0; i < fargs->dim; i++)
+    {	Expression *e = (Expression *)fargs->data[i];
+	printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
+    }
+#endif
+
+    assert((size_t)scope > 0x10000);
+
+    dedargs->setDim(parameters->dim);
+    dedargs->zero();
+
+    dedtypes.setDim(parameters->dim);
+    dedtypes.zero();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    tp = isVariadic();
+
+    nargsi = 0;
+    if (targsi)
+    {	// Set initial template arguments
+
+	nargsi = targsi->dim;
+	if (nargsi > parameters->dim)
+	{   if (!tp)
+		goto Lnomatch;
+	    dedargs->setDim(nargsi);
+	    dedargs->zero();
+	}
+
+	memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data));
+
+	for (i = 0; i < nargsi; i++)
+	{   assert(i < parameters->dim);
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    MATCH m;
+	    Declaration *sparam;
+
+	    m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
+	    //printf("\tdeduceType m = %d\n", m);
+	    if (m == MATCHnomatch)
+		goto Lnomatch;
+	    if (m < match)
+		match = m;
+
+	    sparam->semantic(paramscope);
+	    if (!paramscope->insert(sparam))
+		goto Lnomatch;
+	}
+    }
+
+    assert(fd->type->ty == Tfunction);
+    fdtype = (TypeFunction *)fd->type;
+
+    nfparams = Argument::dim(fdtype->parameters); // number of function parameters
+    nfargs = fargs->dim;		// number of function arguments
+
+    /* Check for match of function arguments with variadic template
+     * parameter, such as:
+     *
+     * template Foo(T, A...) { void Foo(T t, A a); }
+     * void main() { Foo(1,2,3); }
+     */
+    if (tp)				// if variadic
+    {
+	if (nfparams == 0)		// if no function parameters
+	{
+	    Tuple *t = new Tuple();
+	    //printf("t = %p\n", t);
+	    dedargs->data[parameters->dim - 1] = (void *)t;
+	    goto L2;
+	}
+	else if (nfargs < nfparams - 1)
+	    goto L1;
+	else
+	{
+	    /* Figure out which of the function parameters matches
+	     * the tuple template parameter. Do this by matching
+	     * type identifiers.
+	     * Set the index of this function parameter to fptupindex.
+	     */
+	    for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
+	    {
+		Argument *fparam = (Argument *)fdtype->parameters->data[fptupindex];
+		if (fparam->type->ty != Tident)
+		    continue;
+		TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+		if (!tp->ident->equals(tid->ident) || tid->idents.dim)
+		    continue;
+
+		if (fdtype->varargs)	// variadic function doesn't
+		    goto Lnomatch;	// go with variadic template
+
+		/* The types of the function arguments
+		 * now form the tuple argument.
+		 */
+		Tuple *t = new Tuple();
+		dedargs->data[parameters->dim - 1] = (void *)t;
+
+		tuple_dim = nfargs - (nfparams - 1);
+		t->objects.setDim(tuple_dim);
+		for (i = 0; i < tuple_dim; i++)
+		{   Expression *farg = (Expression *)fargs->data[fptupindex + i];
+		    t->objects.data[i] = (void *)farg->type;
+		}
+		goto L2;
+	    }
+	    fptupindex = -1;
+	}
+    }
+
+L1:
+    if (nfparams == nfargs)
+	;
+    else if (nfargs > nfparams)
+    {
+	if (fdtype->varargs == 0)
+	    goto Lnomatch;		// too many args, no match
+	match = MATCHconvert;		// match ... with a conversion
+    }
+
+L2:
+    // Match 'ethis' to any TemplateThisParameter's
+    if (ethis)
+    {
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    TemplateThisParameter *ttp = tp->isTemplateThisParameter();
+	    if (ttp)
+	    {	MATCH m;
+
+		Type *t = new TypeIdentifier(0, ttp->ident);
+		m = ethis->type->deduceType(scope, t, parameters, &dedtypes);
+		if (!m)
+		    goto Lnomatch;
+		if (m < match)
+		    match = m;		// pick worst match
+	    }
+	}
+    }
+
+    // Loop through the function parameters
+    for (i = 0; i < nfparams; i++)
+    {
+	/* Skip over function parameters which wound up
+	 * as part of a template tuple parameter.
+	 */
+	if (i == fptupindex)
+	{   if (fptupindex == nfparams - 1)
+		break;
+	    i += tuple_dim - 1;
+	    continue;
+	}
+
+	Argument *fparam = Argument::getNth(fdtype->parameters, i);
+
+	if (i >= nfargs)		// if not enough arguments
+	{
+	    if (fparam->defaultArg)
+	    {	/* Default arguments do not participate in template argument
+		 * deduction.
+		 */
+		goto Lmatch;
+	    }
+	}
+	else
+	{   Expression *farg = (Expression *)fargs->data[i];
+#if 0
+	    printf("\tfarg->type   = %s\n", farg->type->toChars());
+	    printf("\tfparam->type = %s\n", fparam->type->toChars());
+#endif
+	    MATCH m;
+	    //m = farg->type->toHeadMutable()->deduceType(scope, fparam->type, parameters, &dedtypes);
+	    m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes);
+	    //printf("\tdeduceType m = %d\n", m);
+
+	    /* If no match, see if there's a conversion to a delegate
+	     */
+	    if (!m && fparam->type->toBasetype()->ty == Tdelegate)
+	    {
+		TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype();
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
+		{
+		    m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes);
+		    if (!m && tf->next->toBasetype()->ty == Tvoid)
+			m = MATCHconvert;
+		}
+		//printf("\tm2 = %d\n", m);
+	    }
+
+	    if (m)
+	    {	if (m < match)
+		    match = m;		// pick worst match
+		continue;
+	    }
+	}
+
+	/* The following code for variadic arguments closely
+	 * matches TypeFunction::callMatch()
+	 */
+	if (!(fdtype->varargs == 2 && i + 1 == nfparams))
+	    goto Lnomatch;
+
+	/* Check for match with function parameter T...
+	 */
+	Type *tb = fparam->type->toBasetype();
+	switch (tb->ty)
+	{
+	    // Perhaps we can do better with this, see TypeFunction::callMatch()
+	    case Tsarray:
+	    {	TypeSArray *tsa = (TypeSArray *)tb;
+		integer_t sz = tsa->dim->toInteger();
+		if (sz != nfargs - i)
+		    goto Lnomatch;
+	    }
+	    case Tarray:
+	    {   TypeArray *ta = (TypeArray *)tb;
+		for (; i < nfargs; i++)
+		{
+		    Expression *arg = (Expression *)fargs->data[i];
+		    assert(arg);
+		    MATCH m;
+		    /* If lazy array of delegates,
+		     * convert arg(s) to delegate(s)
+		     */
+		    Type *tret = fparam->isLazyArray();
+		    if (tret)
+		    {
+			if (ta->next->equals(arg->type))
+			{   m = MATCHexact;
+			}
+			else
+			{
+			    m = arg->implicitConvTo(tret);
+			    if (m == MATCHnomatch)
+			    {
+				if (tret->toBasetype()->ty == Tvoid)
+				    m = MATCHconvert;
+			    }
+			}
+		    }
+		    else
+		    {
+			m = arg->type->deduceType(scope, ta->next, parameters, &dedtypes);
+			//m = arg->implicitConvTo(ta->next);
+		    }
+		    if (m == MATCHnomatch)
+			goto Lnomatch;
+		    if (m < match)
+			match = m;
+		}
+		goto Lmatch;
+	    }
+	    case Tclass:
+	    case Tident:
+		goto Lmatch;
+
+	    default:
+		goto Lnomatch;
+	}
+    }
+
+Lmatch:
+
+    /* Fill in any missing arguments with their defaults.
+     */
+    for (i = nargsi; i < dedargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	//printf("tp[%d] = %s\n", i, tp->ident->toChars());
+	/* For T:T*, the dedargs is the T*, dedtypes is the T
+	 * But for function templates, we really need them to match
+	 */
+	Object *oarg = (Object *)dedargs->data[i];
+	Object *oded = (Object *)dedtypes.data[i];
+	//printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+	if (!oarg)
+	{
+	    if (oded)
+	    {
+		if (tp->specialization())
+		{   /* The specialization can work as long as afterwards
+		     * the oded == oarg
+		     */
+		    Declaration *sparam;
+		    dedargs->data[i] = (void *)oded;
+		    MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0);
+		    //printf("m2 = %d\n", m2);
+		    if (!m2)
+			goto Lnomatch;
+		    if (m2 < match)
+			match = m2;		// pick worst match
+		    if (dedtypes.data[i] != oded)
+			error("specialization not allowed for deduced parameter %s", tp->ident->toChars());
+		}
+	    }
+	    else
+	    {	oded = tp->defaultArg(loc, paramscope);
+		if (!oded)
+		    goto Lnomatch;
+	    }
+	    declareParameter(paramscope, tp, oded);
+	    dedargs->data[i] = (void *)oded;
+	}
+    }
+
+    if (constraint)
+    {	/* Check to see if constraint is satisfied.
+	 */
+	Expression *e = constraint->syntaxCopy();
+	paramscope->flags |= SCOPEstaticif;
+	e = e->semantic(paramscope);
+	e = e->optimize(WANTvalue | WANTinterpret);
+        if (e->isBool(TRUE))
+            ;
+        else if (e->isBool(FALSE))
+            goto Lnomatch;
+        else
+        {
+            e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars());
+        }
+    }
+
+
+#if 0
+    for (i = 0; i < dedargs->dim; i++)
+    {	Type *t = (Type *)dedargs->data[i];
+	printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars());
+    }
+#endif
+
+    paramscope->pop();
+    //printf("\tmatch %d\n", match);
+    return match;
+
+Lnomatch:
+    paramscope->pop();
+    //printf("\tnomatch\n");
+    return MATCHnomatch;
+}
+
+/**************************************************
+ * Declare template parameter tp with value o, and install it in the scope sc.
+ */
+
+void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o)
+{
+    //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
+
+    Type *targ = isType(o);
+    Expression *ea = isExpression(o);
+    Dsymbol *sa = isDsymbol(o);
+    Tuple *va = isTuple(o);
+
+    Dsymbol *s;
+
+    if (targ)
+    {
+	//printf("type %s\n", targ->toChars());
+	s = new AliasDeclaration(0, tp->ident, targ);
+    }
+    else if (sa)
+    {
+	//printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
+	s = new AliasDeclaration(0, tp->ident, sa);
+    }
+    else if (ea)
+    {
+	// tdtypes.data[i] always matches ea here
+	Initializer *init = new ExpInitializer(loc, ea);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+
+	Type *t = tvp ? tvp->valType : NULL;
+
+	VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init);
+	v->storage_class = STCmanifest;
+	s = v;
+    }
+    else if (va)
+    {
+	//printf("\ttuple\n");
+	s = new TupleDeclaration(loc, tp->ident, &va->objects);
+    }
+    else
+    {
+#ifdef DEBUG
+	o->print();
+#endif
+	assert(0);
+    }
+    if (!sc->insert(s))
+	error("declaration %s is already defined", tp->ident->toChars());
+    s->semantic(sc);
+}
+
+/**************************************
+ * Determine if TemplateDeclaration is variadic.
+ */
+
+TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
+{   size_t dim = parameters->dim;
+    TemplateTupleParameter *tp = NULL;
+
+    if (dim)
+	tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter();
+    return tp;
+}
+
+TemplateTupleParameter *TemplateDeclaration::isVariadic()
+{
+    return ::isVariadic(parameters);
+}
+
+/***********************************
+ * We can overload templates.
+ */
+
+int TemplateDeclaration::isOverloadable()
+{
+    return 1;
+}
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return that function.
+ * If no match, give error message and return NULL.
+ * Input:
+ *	sc		instantiation scope
+ *	loc		instantiation location
+ *	targsi		initial list of template arguments
+ *	ethis		if !NULL, the 'this' pointer argument
+ *	fargs		arguments to function
+ *	flags		1: do not issue error message on no match, just return NULL
+ */
+
+FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
+	Objects *targsi, Expression *ethis, Expressions *fargs, int flags)
+{
+    MATCH m_best = MATCHnomatch;
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    Objects *tdargs = new Objects();
+    TemplateInstance *ti;
+    FuncDeclaration *fd;
+
+#if 0
+    printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars());
+    printf("    targsi:\n");
+    if (targsi)
+    {	for (int i = 0; i < targsi->dim; i++)
+	{   Object *arg = (Object *)targsi->data[i];
+	    printf("\t%s\n", arg->toChars());
+	}
+    }
+    printf("    fargs:\n");
+    for (int i = 0; i < fargs->dim; i++)
+    {	Expression *arg = (Expression *)fargs->data[i];
+	printf("\t%s %s\n", arg->type->toChars(), arg->toChars());
+	//printf("\tty = %d\n", arg->type->ty);
+    }
+#endif
+
+    for (TemplateDeclaration *td = this; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    error("forward reference to template %s", td->toChars());
+	    goto Lerror;
+	}
+	if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration())
+	{
+	    error("is not a function template");
+	    goto Lerror;
+	}
+
+	MATCH m;
+	Objects dedargs;
+
+	m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs);
+	//printf("deduceFunctionTemplateMatch = %d\n", m);
+	if (!m)			// if no match
+	    continue;
+
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	MATCH c1 = td->leastAsSpecialized(td_best);
+	MATCH c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 > c2)
+	    goto Ltd;
+	else if (c1 < c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	assert((size_t)td->scope > 0x10000);
+	td_best = td;
+	m_best = m;
+	tdargs->setDim(dedargs.dim);
+	memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *));
+	continue;
+    }
+    if (!td_best)
+    {
+	if (!(flags & 1))
+	    error(loc, "does not match any function template declaration");
+	goto Lerror;
+    }
+    if (td_ambig)
+    {
+	error(loc, "matches more than one function template declaration:\n  %s\nand:\n  %s",
+		td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best with arguments tdargs.
+     * Now instantiate the template.
+     */
+    assert((size_t)td_best->scope > 0x10000);
+    ti = new TemplateInstance(loc, td_best, tdargs);
+    ti->semantic(sc);
+    fd = ti->toAlias()->isFuncDeclaration();
+    if (!fd)
+	goto Lerror;
+    return fd;
+
+  Lerror:
+    if (!(flags & 1))
+    {
+	HdrGenState hgs;
+
+	OutBuffer bufa;
+	Objects *args = targsi;
+	if (args)
+	{   for (int i = 0; i < args->dim; i++)
+	    {
+		if (i)
+		    bufa.writeByte(',');
+		Object *oarg = (Object *)args->data[i];
+		ObjectToCBuffer(&bufa, &hgs, oarg);
+	    }
+	}
+
+	OutBuffer buf;
+	argExpTypesToCBuffer(&buf, fargs, &hgs);
+
+	error(loc, "cannot deduce template function from argument types !(%s)(%s)",
+		bufa.toChars(), buf.toChars());
+    }
+    return NULL;
+}
+
+void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+#if 0 // Should handle template functions
+    if (onemember && onemember->isFuncDeclaration())
+	buf->writestring("foo ");
+#endif
+    buf->writestring(kind());
+    buf->writeByte(' ');
+    buf->writestring(ident->toChars());
+    buf->writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (hgs->ddoc)
+	    tp = (TemplateParameter *)origParameters->data[i];
+	if (i)
+	    buf->writeByte(',');
+	tp->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(')');
+
+    if (constraint)
+    {	buf->writestring(" if (");
+	constraint->toCBuffer(buf, hgs);
+	buf->writeByte(')');
+    }
+
+    if (hgs->hdrgen)
+    {
+	hgs->tpltMember++;
+	buf->writenl();
+	buf->writebyte('{');
+	buf->writenl();
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writebyte('}');
+	buf->writenl();
+	hgs->tpltMember--;
+    }
+}
+
+
+char *TemplateDeclaration::toChars()
+{   OutBuffer buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf.writestring(ident->toChars());
+    buf.writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (i)
+	    buf.writeByte(',');
+	tp->toCBuffer(&buf, &hgs);
+    }
+    buf.writeByte(')');
+
+    if (constraint)
+    {	buf.writestring(" if (");
+	constraint->toCBuffer(&buf, &hgs);
+	buf.writeByte(')');
+    }
+
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return -1 if not found.
+ */
+
+int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
+{
+    for (size_t i = 0; i < parameters->dim; i++)
+    {   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	if (tp->ident->equals(id))
+	    return i;
+    }
+    return -1;
+}
+
+int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
+{
+    assert(tparam->ty == Tident);
+    TypeIdentifier *tident = (TypeIdentifier *)tparam;
+    //printf("\ttident = '%s'\n", tident->toChars());
+    if (tident->idents.dim == 0)
+    {
+	return templateIdentifierLookup(tident->ident, parameters);
+    }
+    return -1;
+}
+
+/* These form the heart of template argument deduction.
+ * Given 'this' being the type argument to the template instance,
+ * it is matched against the template declaration parameter specialization
+ * 'tparam' to determine the type to be used for the parameter.
+ * Example:
+ *	template Foo(T:T*)	// template declaration
+ *	Foo!(int*)		// template instantiation
+ * Input:
+ *	this = int*
+ *	tparam = T
+ *	parameters = [ T:T* ]	// Array of TemplateParameter's
+ * Output:
+ *	dedtypes = [ int ]	// Array of Expression/Type's
+ */
+
+MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+#if 0
+    printf("Type::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+    if (!tparam)
+	goto Lnomatch;
+
+    if (this == tparam)
+	goto Lexact;
+
+    if (tparam->ty == Tident)
+    {
+	// Determine which parameter tparam is
+	int i = templateParameterLookup(tparam, parameters);
+	if (i == -1)
+	{
+	    if (!sc)
+		goto Lnomatch;
+
+	    /* Need a loc to go with the semantic routine.
+	     */
+	    Loc loc;
+	    if (parameters->dim)
+	    {
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[0];
+		loc = tp->loc;
+	    }
+
+	    /* BUG: what if tparam is a template instance, that
+	     * has as an argument another Tident?
+	     */
+	    tparam = tparam->semantic(loc, sc);
+	    assert(tparam->ty != Tident);
+	    return deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	// Found the corresponding parameter tp
+	if (!tp->isTemplateTypeParameter())
+	    goto Lnomatch;
+	Type *tt = this;
+	Type *at = (Type *)dedtypes->data[i];
+
+	// 3*3 == 9 cases
+	if (tparam->isMutable())
+	{   // foo(U:U) T            => T
+	    // foo(U:U) const(T)     => const(T)
+	    // foo(U:U) invariant(T) => invariant(T)
+	    if (!at)
+	    {   dedtypes->data[i] = (void *)this;
+		goto Lexact;
+	    }
+	}
+	else if (mod == tparam->mod)
+	{   // foo(U:const(U))     const(T)     => T
+	    // foo(U:invariant(U)) invariant(T) => T
+	    tt = mutableOf();
+	    if (!at)
+	    {   dedtypes->data[i] = (void *)tt;
+		goto Lexact;
+	    }
+	}
+	else if (tparam->isConst())
+	{   // foo(U:const(U)) T            => T
+	    // foo(U:const(U)) invariant(T) => T
+	    tt = mutableOf();
+	    if (!at)
+	    {   dedtypes->data[i] = (void *)tt;
+		goto Lconst;
+	    }
+	}
+	else
+	{   // foo(U:invariant(U)) T        => nomatch
+	    // foo(U:invariant(U)) const(T) => nomatch
+	    if (!at)
+		goto Lnomatch;
+	}
+
+	if (tt->equals(at))
+	    goto Lexact;
+	else if (tt->ty == Tclass && at->ty == Tclass)
+	{
+	    return tt->implicitConvTo(at);
+	}
+	else if (tt->ty == Tsarray && at->ty == Tarray &&
+	    tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst)
+	{
+	    goto Lexact;
+	}
+	else
+	    goto Lnomatch;
+    }
+
+    if (ty != tparam->ty)
+	return implicitConvTo(tparam);
+//	goto Lnomatch;
+
+    if (nextOf())
+	return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+
+Lexact:
+    return MATCHexact;
+
+Lnomatch:
+    return MATCHnomatch;
+
+Lconst:
+    return MATCHconst;
+}
+
+MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+#if 0
+    printf("TypeSArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+    // Extra check that array dimensions must match
+    if (tparam)
+    {
+	if (tparam->ty == Tsarray)
+	{
+	    TypeSArray *tp = (TypeSArray *)tparam;
+
+	    if (tp->dim->op == TOKvar &&
+		((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter)
+	    {	int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters);
+		// This code matches code in TypeInstance::deduceType()
+		if (i == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+		TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+		if (!tvp)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[i];
+		if (e)
+		{
+		    if (!dim->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tvp->valType->semantic(0, sc);
+		    MATCH m = (MATCH)dim->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[i] = dim;
+		}
+	    }
+	    else if (dim->toInteger() != tp->dim->toInteger())
+		return MATCHnomatch;
+	}
+	else if (tparam->ty == Taarray)
+	{
+	    TypeAArray *tp = (TypeAArray *)tparam;
+	    if (tp->index->ty == Tident)
+	    {	TypeIdentifier *tident = (TypeIdentifier *)tp->index;
+
+		if (tident->idents.dim == 0)
+		{   Identifier *id = tident->ident;
+
+		    for (size_t i = 0; i < parameters->dim; i++)
+		    {
+			TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+			if (tp->ident->equals(id))
+			{   // Found the corresponding template parameter
+			    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+			    if (!tvp || !tvp->valType->isintegral())
+				goto Lnomatch;
+
+			    if (dedtypes->data[i])
+			    {
+				if (!dim->equals((Object *)dedtypes->data[i]))
+				    goto Lnomatch;
+			    }
+			    else
+			    {	dedtypes->data[i] = (void *)dim;
+			    }
+			    return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+			}
+		    }
+		}
+	    }
+	}
+	else if (tparam->ty == Tarray)
+	{   MATCH m;
+
+	    m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+	    if (m == MATCHexact)
+		m = MATCHconvert;
+	    return m;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+  Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+#if 0
+    printf("TypeAArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+    // Extra check that index type must match
+    if (tparam && tparam->ty == Taarray)
+    {
+	TypeAArray *tp = (TypeAArray *)tparam;
+	if (!index->deduceType(sc, tp->index, parameters, dedtypes))
+	{
+	    return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeFunction::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check that function characteristics must match
+    if (tparam && tparam->ty == Tfunction)
+    {
+	TypeFunction *tp = (TypeFunction *)tparam;
+	if (varargs != tp->varargs ||
+	    linkage != tp->linkage)
+	    return MATCHnomatch;
+
+	size_t nfargs = Argument::dim(this->parameters);
+	size_t nfparams = Argument::dim(tp->parameters);
+
+	/* See if tuple match
+	 */
+	if (nfparams > 0 && nfargs >= nfparams - 1)
+	{
+	    /* See if 'A' of the template parameter matches 'A'
+	     * of the type of the last function parameter.
+	     */
+	    Argument *fparam = (Argument *)tp->parameters->data[nfparams - 1];
+	    if (fparam->type->ty != Tident)
+		goto L1;
+	    TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+	    if (tid->idents.dim)
+		goto L1;
+
+	    /* Look through parameters to find tuple matching tid->ident
+	     */
+	    size_t tupi = 0;
+	    for (; 1; tupi++)
+	    {	if (tupi == parameters->dim)
+		    goto L1;
+		TemplateParameter *t = (TemplateParameter *)parameters->data[tupi];
+		TemplateTupleParameter *tup = t->isTemplateTupleParameter();
+		if (tup && tup->ident->equals(tid->ident))
+		    break;
+	    }
+
+	    /* The types of the function arguments [nfparams - 1 .. nfargs]
+	     * now form the tuple argument.
+	     */
+	    int tuple_dim = nfargs - (nfparams - 1);
+
+	    /* See if existing tuple, and whether it matches or not
+	     */
+	    Object *o = (Object *)dedtypes->data[tupi];
+	    if (o)
+	    {	// Existing deduced argument must be a tuple, and must match
+		Tuple *t = isTuple(o);
+		if (!t || t->objects.dim != tuple_dim)
+		    return MATCHnomatch;
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    if (!arg->type->equals((Object *)t->objects.data[i]))
+			return MATCHnomatch;
+		}
+	    }
+	    else
+	    {	// Create new tuple
+		Tuple *t = new Tuple();
+		t->objects.setDim(tuple_dim);
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    t->objects.data[i] = (void *)arg->type;
+		}
+		dedtypes->data[tupi] = (void *)t;
+	    }
+	    nfparams--;	// don't consider the last parameter for type deduction
+	    goto L2;
+	}
+
+    L1:
+	if (nfargs != nfparams)
+	    return MATCHnomatch;
+    L2:
+	for (size_t i = 0; i < nfparams; i++)
+	{
+	    Argument *a = Argument::getNth(this->parameters, i);
+	    Argument *ap = Argument::getNth(tp->parameters, i);
+	    if (a->storageClass != ap->storageClass ||
+		!a->type->deduceType(sc, ap->type, parameters, dedtypes))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tident)
+    {
+	TypeIdentifier *tp = (TypeIdentifier *)tparam;
+
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id1 = (Identifier *)idents.data[i];
+	    Identifier *id2 = (Identifier *)tp->idents.data[i];
+
+	    if (!id1->equals(id2))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeInstance::deduceType(Scope *sc,
+	Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+    //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars());
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check
+    if (tparam && tparam->ty == Tinstance)
+    {
+	TypeInstance *tp = (TypeInstance *)tparam;
+
+	//printf("tempinst->tempdecl = %p\n", tempinst->tempdecl);
+	//printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
+	if (!tp->tempinst->tempdecl)
+	{   //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
+	    if (!tp->tempinst->name->equals(tempinst->name))
+	    {
+		/* Handle case of:
+		 *  template Foo(T : sa!(T), alias sa)
+		 */
+		int i = templateIdentifierLookup(tp->tempinst->name, parameters);
+		if (i == -1)
+		{   /* Didn't find it as a parameter identifier. Try looking
+		     * it up and seeing if is an alias. See Bugzilla 1454
+		     */
+		    Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL);
+		    if (s)
+		    {
+			s = s->toAlias();
+			TemplateDeclaration *td = s->isTemplateDeclaration();
+			if (td && td == tempinst->tempdecl)
+			    goto L2;
+		    }
+		    goto Lnomatch;
+		}
+		TemplateParameter *tpx = (TemplateParameter *)parameters->data[i];
+		// This logic duplicates tpx->matchArg()
+		TemplateAliasParameter *ta = tpx->isTemplateAliasParameter();
+		if (!ta)
+		    goto Lnomatch;
+		Object *sa = tempinst->tempdecl;
+		if (!sa)
+		    goto Lnomatch;
+		if (ta->specAlias && sa != ta->specAlias)
+		    goto Lnomatch;
+		if (dedtypes->data[i])
+		{   // Must match already deduced symbol
+		    Object *s = (Object *)dedtypes->data[i];
+
+		    if (s != sa)
+			goto Lnomatch;
+		}
+		dedtypes->data[i] = sa;
+	    }
+	}
+	else if (tempinst->tempdecl != tp->tempinst->tempdecl)
+	    goto Lnomatch;
+
+      L2:
+	if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim)
+	    goto Lnomatch;
+
+	for (int i = 0; i < tempinst->tiargs->dim; i++)
+	{
+	    //printf("\ttest: tempinst->tiargs[%d]\n", i);
+	    int j;
+	    Object *o1 = (Object *)tempinst->tiargs->data[i];
+	    Object *o2 = (Object *)tp->tempinst->tiargs->data[i];
+
+	    Type *t1 = isType(o1);
+	    Type *t2 = isType(o2);
+
+	    Expression *e1 = isExpression(o1);
+	    Expression *e2 = isExpression(o2);
+
+#if 0
+	    if (t1)	printf("t1 = %s\n", t1->toChars());
+	    if (t2)	printf("t2 = %s\n", t2->toChars());
+	    if (e1)	printf("e1 = %s\n", e1->toChars());
+	    if (e2)	printf("e2 = %s\n", e2->toChars());
+#endif
+
+	    if (t1 && t2)
+	    {
+		if (!t1->deduceType(sc, t2, parameters, dedtypes))
+		    goto Lnomatch;
+	    }
+	    else if (e1 && e2)
+	    {
+		if (!e1->equals(e2))
+		{   if (e2->op == TOKvar)
+		    {
+			/*
+			 * (T:Number!(e2), int e2)
+			 */
+			j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
+			goto L1;
+		    }
+		    goto Lnomatch;
+		}
+	    }
+	    else if (e1 && t2 && t2->ty == Tident)
+	    {
+		j = templateParameterLookup(t2, parameters);
+	    L1:
+		if (j == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[j];
+		// BUG: use tp->matchArg() instead of the following
+		TemplateValueParameter *tv = tp->isTemplateValueParameter();
+		if (!tv)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[j];
+		if (e)
+		{
+		    if (!e1->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tv->valType->semantic(0, sc);
+		    MATCH m = (MATCH)e1->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[j] = e1;
+		}
+	    }
+	    // BUG: Need to handle alias and tuple parameters
+	    else
+		goto Lnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeStruct::deduceType()\n");
+    //printf("\tthis->parent   = %s, ", sym->parent->toChars()); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    /* If this struct is a template struct, and we're matching
+     * it against a template instance, convert the struct type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tstruct)
+    {
+	TypeStruct *tp = (TypeStruct *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tenum)
+    {
+	TypeEnum *tp = (TypeEnum *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Ttypedef)
+    {
+	TypeTypedef *tp = (TypeTypedef *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeClass::deduceType(this = %s)\n", toChars());
+
+    /* If this class is a template class, and we're matching
+     * it against a template instance, convert the class type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tclass)
+    {
+	TypeClass *tp = (TypeClass *)tparam;
+
+	//printf("\t%d\n", (MATCH) implicitConvTo(tp));
+	return implicitConvTo(tp);
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+/* ======================== TemplateParameter =============================== */
+
+TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->sparam = NULL;
+}
+
+TemplateTypeParameter  *TemplateParameter::isTemplateTypeParameter()
+{
+    return NULL;
+}
+
+TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
+{
+    return NULL;
+}
+
+TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
+{
+    return NULL;
+}
+
+TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
+{
+    return NULL;
+}
+
+#if DMDV2
+TemplateThisParameter  *TemplateParameter::isTemplateThisParameter()
+{
+    return NULL;
+}
+#endif
+
+/* ======================== TemplateTypeParameter =========================== */
+
+// type-parameter
+
+TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
+	Type *defaultType)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specType = specType;
+    this->defaultType = defaultType;
+}
+
+TemplateTypeParameter  *TemplateTypeParameter::isTemplateTypeParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTypeParameter::syntaxCopy()
+{
+    TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    if (defaultType)
+	tp->defaultType = defaultType->syntaxCopy();
+    return tp;
+}
+
+void TemplateTypeParameter::declareParameter(Scope *sc)
+{
+    //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTypeParameter::semantic(Scope *sc)
+{
+    //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+    if (specType)
+    {
+	specType = specType->semantic(loc, sc);
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultType)
+    {
+	defaultType = defaultType->semantic(loc, sc);
+    }
+#endif
+}
+
+/****************************************
+ * Determine if two TemplateParameters are the same
+ * as far as TemplateDeclaration overloading goes.
+ * Returns:
+ *	1	match
+ *	0	no match
+ */
+
+int TemplateTypeParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+    if (ttp)
+    {
+	if (specType != ttp->specType)
+	    goto Lnomatch;
+
+	if (specType && !specType->equals(ttp->specType))
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ *	i		i'th argument
+ *	tiargs[]	actual arguments to template instance
+ *	parameters[]	template parameters
+ *	dedtypes[]	deduced arguments to template instance
+ *	*psparam	set to symbol declared and initialized to dedtypes[i]
+ *	flags		1: don't do 'toHeadMutable()'
+ */
+
+MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs,
+	int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam, int flags)
+{
+    //printf("TemplateTypeParameter::matchArg()\n");
+    Type *t;
+    Object *oarg;
+    MATCH m = MATCHexact;
+    Type *ta;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(loc, sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+	    {
+		goto Lnomatch;
+	    }
+	    flags |= 1;		// already deduced, so don't to toHeadMutable()
+	}
+    }
+
+    ta = isType(oarg);
+    if (!ta)
+    {
+	//printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
+	goto Lnomatch;
+    }
+    //printf("ta is %s\n", ta->toChars());
+
+    t = (Type *)dedtypes->data[i];
+
+    if (specType)
+    {
+	//printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars());
+	MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes);
+	if (m2 == MATCHnomatch)
+	{   //printf("\tfailed deduceType\n");
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+	t = (Type *)dedtypes->data[i];
+    }
+    else
+    {
+	// So that matches with specializations are better
+	m = MATCHconvert;
+
+	/* This is so that:
+	 *   template Foo(T), Foo!(const int), => ta == int
+	 */
+//	if (!(flags & 1))
+//	    ta = ta->toHeadMutable();
+
+	if (t)
+	{   // Must match already deduced type
+
+	    m = MATCHexact;
+	    if (!t->equals(ta))
+	    {	//printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+		goto Lnomatch;
+	    }
+	}
+    }
+
+    if (!t)
+    {
+	dedtypes->data[i] = ta;
+	t = ta;
+    }
+    *psparam = new AliasDeclaration(loc, ident, t);
+    //printf("\tm = %d\n", m);
+    return m;
+
+Lnomatch:
+    *psparam = NULL;
+    //printf("\tm = %d\n", MATCHnomatch);
+    return MATCHnomatch;
+}
+
+
+void TemplateTypeParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Type *t  = isType(oarg);
+    Type *ta = isType(oded);
+
+    assert(ta);
+
+    if (specType)
+	printf("\tSpecialization: %s\n", specType->toChars());
+    if (defaultType)
+	printf("\tDefault:        %s\n", defaultType->toChars());
+    printf("\tArgument:       %s\n", t ? t->toChars() : "NULL");
+    printf("\tDeduced Type:   %s\n", ta->toChars());
+}
+
+
+void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    if (specType)
+    {
+	buf->writestring(" : ");
+	specType->toCBuffer(buf, NULL, hgs);
+    }
+    if (defaultType)
+    {
+	buf->writestring(" = ");
+	defaultType->toCBuffer(buf, NULL, hgs);
+    }
+}
+
+
+void *TemplateTypeParameter::dummyArg()
+{   Type *t;
+
+    if (specType)
+	t = specType;
+    else
+    {   // Use this for alias-parameter's too (?)
+	t = new TypeIdentifier(loc, ident);
+    }
+    return (void *)t;
+}
+
+
+Object *TemplateTypeParameter::specialization()
+{
+    return specType;
+}
+
+
+Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc)
+{
+    Type *t;
+
+    t = defaultType;
+    if (t)
+    {
+	t = t->syntaxCopy();
+	t = t->semantic(loc, sc);
+    }
+    return t;
+}
+
+/* ======================== TemplateThisParameter =========================== */
+
+#if DMDV2
+// this-parameter
+
+TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident,
+	Type *specType,
+	Type *defaultType)
+    : TemplateTypeParameter(loc, ident, specType, defaultType)
+{
+}
+
+TemplateThisParameter  *TemplateThisParameter::isTemplateThisParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateThisParameter::syntaxCopy()
+{
+    TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    if (defaultType)
+	tp->defaultType = defaultType->syntaxCopy();
+    return tp;
+}
+
+void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("this ");
+    TemplateTypeParameter::toCBuffer(buf, hgs);
+}
+#endif
+
+/* ======================== TemplateAliasParameter ========================== */
+
+// alias-parameter
+
+Dsymbol *TemplateAliasParameter::sdummy = NULL;
+
+TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident,
+	Type *specType, Object *specAlias, Object *defaultAlias)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specType = specType;
+    this->specAlias = specAlias;
+    this->defaultAlias = defaultAlias;
+}
+
+TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateAliasParameter::syntaxCopy()
+{
+    TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    tp->specAlias = objectSyntaxCopy(specAlias);
+    tp->defaultAlias = objectSyntaxCopy(defaultAlias);
+    return tp;
+}
+
+void TemplateAliasParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o)
+{
+    if (o)
+    {
+	Expression *ea = isExpression(o);
+	Type *ta = isType(o);
+	if (ta)
+	{   Dsymbol *s = ta->toDsymbol(sc);
+	    if (s)
+		o = s;
+	    else
+		o = ta->semantic(loc, sc);
+	}
+	else if (ea)
+	{
+	    ea = ea->semantic(sc);
+	    o = ea->optimize(WANTvalue | WANTinterpret);
+	}
+    }
+    return o;
+}
+
+void TemplateAliasParameter::semantic(Scope *sc)
+{
+    if (specType)
+    {
+	specType = specType->semantic(loc, sc);
+    }
+    specAlias = aliasParameterSemantic(loc, sc, specAlias);
+#if 0 // Don't do semantic() until instantiation
+    if (defaultAlias)
+	defaultAlias = defaultAlias->semantic(loc, sc);
+#endif
+}
+
+int TemplateAliasParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateAliasParameter *tap = tp->isTemplateAliasParameter();
+
+    if (tap)
+    {
+	if (specAlias != tap->specAlias)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateAliasParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters,
+	Objects *dedtypes,
+	Declaration **psparam, int flags)
+{
+    Object *sa;
+    Object *oarg;
+    Expression *ea;
+    Dsymbol *s;
+
+    //printf("TemplateAliasParameter::matchArg()\n");
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(loc, sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    sa = getDsymbol(oarg);
+    if (sa)
+    {
+	/* specType means the alias must be a declaration with a type
+	 * that matches specType.
+	 */
+	if (specType)
+	{   Declaration *d = ((Dsymbol *)sa)->isDeclaration();
+	    if (!d)
+		goto Lnomatch;
+	    if (!d->type->equals(specType))
+		goto Lnomatch;
+	}
+    }
+    else
+    {
+	sa = oarg;
+	ea = isExpression(oarg);
+	if (ea)
+	{   if (specType)
+	    {
+		if (!ea->type->equals(specType))
+		    goto Lnomatch;
+	    }
+	}
+	else
+	    goto Lnomatch;
+    }
+
+    if (specAlias)
+    {
+	if (sa == sdummy)
+	    goto Lnomatch;
+	if (sa != specAlias)
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced symbol
+	Object *s = (Object *)dedtypes->data[i];
+
+	if (!sa || s != sa)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = sa;
+
+    s = isDsymbol(sa);
+    if (s)
+	*psparam = new AliasDeclaration(loc, ident, s);
+    else
+    {
+	assert(ea);
+
+        // Declare manifest constant
+        Initializer *init = new ExpInitializer(loc, ea);
+        VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+        v->storage_class = STCmanifest;
+        v->semantic(sc);
+	*psparam = v;
+    }
+    return MATCHexact;
+
+Lnomatch:
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateAliasParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Dsymbol *sa = isDsymbol(oded);
+    assert(sa);
+
+    printf("\tArgument alias: %s\n", sa->toChars());
+}
+
+void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+    if (specType)
+    {	HdrGenState hgs;
+	specType->toCBuffer(buf, ident, &hgs);
+    }
+    else
+	buf->writestring(ident->toChars());
+    if (specAlias)
+    {
+	buf->writestring(" : ");
+	ObjectToCBuffer(buf, hgs, specAlias);
+    }
+    if (defaultAlias)
+    {
+	buf->writestring(" = ");
+	ObjectToCBuffer(buf, hgs, defaultAlias);
+    }
+}
+
+
+void *TemplateAliasParameter::dummyArg()
+{   Object *s;
+
+    s = specAlias;
+    if (!s)
+    {
+	if (!sdummy)
+	    sdummy = new Dsymbol();
+	s = sdummy;
+    }
+    return (void*)s;
+}
+
+
+Object *TemplateAliasParameter::specialization()
+{
+    return specAlias;
+}
+
+
+Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc)
+{
+    Object *o = aliasParameterSemantic(loc, sc, defaultAlias);
+    return o;
+}
+
+/* ======================== TemplateValueParameter ========================== */
+
+// value-parameter
+
+Expression *TemplateValueParameter::edummy = NULL;
+
+TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
+	Expression *specValue, Expression *defaultValue)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->valType = valType;
+    this->specValue = specValue;
+    this->defaultValue = defaultValue;
+}
+
+TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateValueParameter::syntaxCopy()
+{
+    TemplateValueParameter *tp =
+	new TemplateValueParameter(loc, ident, valType, specValue, defaultValue);
+    tp->valType = valType->syntaxCopy();
+    if (specValue)
+	tp->specValue = specValue->syntaxCopy();
+    if (defaultValue)
+	tp->defaultValue = defaultValue->syntaxCopy();
+    return tp;
+}
+
+void TemplateValueParameter::declareParameter(Scope *sc)
+{
+    VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
+    v->storage_class = STCtemplateparameter;
+    if (!sc->insert(v))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+    sparam = v;
+}
+
+void TemplateValueParameter::semantic(Scope *sc)
+{
+    sparam->semantic(sc);
+    valType = valType->semantic(loc, sc);
+    if (!(valType->isintegral() || valType->isfloating() || valType->isString()) &&
+	valType->ty != Tident)
+	error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars());
+
+    if (specValue)
+    {   Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64 || e->op == TOKfloat64 ||
+	    e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring)
+	    specValue = e;
+	//e->toInteger();
+    }
+
+#if 0	// defer semantic analysis to arg match
+    if (defaultValue)
+    {   Expression *e = defaultValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64)
+	    defaultValue = e;
+	//e->toInteger();
+    }
+#endif
+}
+
+int TemplateValueParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+
+    if (tvp)
+    {
+	if (valType != tvp->valType)
+	    goto Lnomatch;
+
+	if (valType && !valType->equals(tvp->valType))
+	    goto Lnomatch;
+
+	if (specValue != tvp->specValue)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+
+MATCH TemplateValueParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam, int flags)
+{
+    //printf("TemplateValueParameter::matchArg()\n");
+
+    Initializer *init;
+    Declaration *sparam;
+    MATCH m = MATCHexact;
+    Expression *ei;
+    Object *oarg;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(loc, sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    ei = isExpression(oarg);
+    Type *vt;
+
+    if (!ei && oarg)
+	goto Lnomatch;
+
+    if (ei && ei->op == TOKvar)
+    {	// Resolve const variables that we had skipped earlier
+	ei = ei->optimize(WANTvalue | WANTinterpret);
+    }
+
+    if (specValue)
+    {
+	if (!ei || ei == edummy)
+	    goto Lnomatch;
+
+	Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	//e->type = e->type->toHeadMutable();
+
+	ei = ei->syntaxCopy();
+	ei = ei->semantic(sc);
+	ei = ei->optimize(WANTvalue | WANTinterpret);
+	//ei->type = ei->type->toHeadMutable();
+	//printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars());
+	//printf("\te : %s, %s\n", e->toChars(), e->type->toChars());
+	if (!ei->equals(e))
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced value
+	Expression *e = (Expression *)dedtypes->data[i];
+
+	if (!ei || !ei->equals(e))
+	    goto Lnomatch;
+    }
+Lmatch:
+    //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty);
+    vt = valType->semantic(0, sc);
+    //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars());
+    //printf("vt = %s\n", vt->toChars());
+    if (ei->type)
+    {
+	//ei->type = ei->type->toHeadMutable();
+	m = (MATCH)ei->implicitConvTo(vt);
+	//printf("m: %d\n", m);
+	if (!m)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = ei;
+
+    init = new ExpInitializer(loc, ei);
+    sparam = new VarDeclaration(loc, vt, ident, init);
+    sparam->storage_class = STCmanifest;
+    *psparam = sparam;
+    return m;
+
+Lnomatch:
+    //printf("\tno match\n");
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateValueParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Expression *ea = isExpression(oded);
+
+    if (specValue)
+	printf("\tSpecialization: %s\n", specValue->toChars());
+    printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL");
+}
+
+
+void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    valType->toCBuffer(buf, ident, hgs);
+    if (specValue)
+    {
+	buf->writestring(" : ");
+	specValue->toCBuffer(buf, hgs);
+    }
+    if (defaultValue)
+    {
+	buf->writestring(" = ");
+	defaultValue->toCBuffer(buf, hgs);
+    }
+}
+
+
+void *TemplateValueParameter::dummyArg()
+{   Expression *e;
+
+    e = specValue;
+    if (!e)
+    {
+	// Create a dummy value
+	if (!edummy)
+	    edummy = valType->defaultInit();
+	e = edummy;
+    }
+    return (void *)e;
+}
+
+
+Object *TemplateValueParameter::specialization()
+{
+    return specValue;
+}
+
+
+Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc)
+{
+    Expression *e = defaultValue;
+    if (e)
+    {
+	e = e->syntaxCopy();
+	e = e->semantic(sc);
+#if DMDV2
+	if (e->op == TOKdefault)
+	{   DefaultInitExp *de = (DefaultInitExp *)e;
+	    e = de->resolve(loc, sc);
+	}
+#endif
+    }
+    return e;
+}
+
+/* ======================== TemplateTupleParameter ========================== */
+
+// variadic-parameter
+
+TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+}
+
+TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTupleParameter::syntaxCopy()
+{
+    TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident);
+    return tp;
+}
+
+void TemplateTupleParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTupleParameter::semantic(Scope *sc)
+{
+}
+
+int TemplateTupleParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTupleParameter *tvp = tp->isTemplateTupleParameter();
+
+    if (tvp)
+    {
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateTupleParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters,
+	Objects *dedtypes,
+	Declaration **psparam, int flags)
+{
+    //printf("TemplateTupleParameter::matchArg()\n");
+
+    /* The rest of the actual arguments (tiargs[]) form the match
+     * for the variadic parameter.
+     */
+    assert(i + 1 == dedtypes->dim);	// must be the last one
+    Tuple *ovar;
+    if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i]))
+	ovar = isTuple((Object *)tiargs->data[i]);
+    else
+    {
+	ovar = new Tuple();
+	//printf("ovar = %p\n", ovar);
+	if (i < tiargs->dim)
+	{
+	    //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim);
+	    ovar->objects.setDim(tiargs->dim - i);
+	    for (size_t j = 0; j < ovar->objects.dim; j++)
+		ovar->objects.data[j] = tiargs->data[i + j];
+	}
+    }
+    *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
+    dedtypes->data[i] = (void *)ovar;
+    return MATCHexact;
+}
+
+
+void TemplateTupleParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s... [", ident->toChars());
+    Tuple *v = isTuple(oded);
+    assert(v);
+
+    //printf("|%d| ", v->objects.dim);
+    for (int i = 0; i < v->objects.dim; i++)
+    {
+	if (i)
+	    printf(", ");
+
+	Object *o = (Object *)v->objects.data[i];
+
+	Dsymbol *sa = isDsymbol(o);
+	if (sa)
+	    printf("alias: %s", sa->toChars());
+
+	Type *ta = isType(o);
+	if (ta)
+	    printf("type: %s", ta->toChars());
+
+	Expression *ea = isExpression(o);
+	if (ea)
+	    printf("exp: %s", ea->toChars());
+
+	assert(!isTuple(o));		// no nested Tuple arguments
+    }
+
+    printf("]\n");
+}
+
+void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    buf->writestring("...");
+}
+
+
+void *TemplateTupleParameter::dummyArg()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::specialization()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc)
+{
+    return NULL;
+}
+
+/* ======================== TemplateInstance ================================ */
+
+TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null");
+#endif
+    this->loc = loc;
+    this->name = ident;
+    this->tiargs = NULL;
+    this->tempdecl = NULL;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->semantictiargsdone = 0;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 0;
+    this->isnested = NULL;
+    this->errors = 0;
+    this->tinst = NULL;
+}
+
+/*****************
+ * This constructor is only called when we figured out which function
+ * template to instantiate.
+ */
+
+TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars());
+#endif
+    this->loc = loc;
+    this->name = td->ident;
+    this->tiargs = tiargs;
+    this->tempdecl = td;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->semantictiargsdone = 1;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 1;
+    this->isnested = NULL;
+    this->errors = 0;
+    this->tinst = NULL;
+
+    assert((size_t)tempdecl->scope > 0x10000);
+}
+
+
+Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
+{
+    Objects *a = NULL;
+    if (objs)
+    {	a = new Objects();
+	a->setDim(objs->dim);
+	for (size_t i = 0; i < objs->dim; i++)
+	{
+	    a->data[i] = objectSyntaxCopy((Object *)objs->data[i]);
+	}
+    }
+    return a;
+}
+
+Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
+{
+    TemplateInstance *ti;
+
+    if (s)
+	ti = (TemplateInstance *)s;
+    else
+	ti = new TemplateInstance(loc, name);
+
+    ti->tiargs = arraySyntaxCopy(tiargs);
+
+    ScopeDsymbol::syntaxCopy(ti);
+    return ti;
+}
+
+
+void TemplateInstance::semantic(Scope *sc)
+{
+    if (global.errors)
+    {
+	if (!global.gag)
+	{
+	    /* Trying to soldier on rarely generates useful messages
+	     * at this point.
+	     */
+	    fatal();
+	}
+	return;
+    }
+#if LOG
+    printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+    if (inst)		// if semantic() was already run
+    {
+#if LOG
+	printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst);
+#endif
+	return;
+    }
+
+    if (semanticdone != 0)
+    {
+	error(loc, "recursive template expansion");
+//	inst = this;
+	return;
+    }
+    semanticdone = 1;
+
+    // get the enclosing template instance from the scope tinst
+    tinst = sc->tinst;
+
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+    if (havetempdecl)
+    {
+	assert((size_t)tempdecl->scope > 0x10000);
+	// Deduce tdtypes
+	tdtypes.setDim(tempdecl->parameters->dim);
+	if (!tempdecl->matchWithInstance(this, &tdtypes, 2))
+	{
+	    error("incompatible arguments for template instantiation");
+	    inst = this;
+	    return;
+	}
+    }
+    else
+    {
+	/* Run semantic on each argument, place results in tiargs[]
+	 * (if we havetempdecl, then tiargs is already evaluated)
+	 */
+	semanticTiargs(sc);
+
+	tempdecl = findTemplateDeclaration(sc);
+	if (tempdecl)
+	    tempdecl = findBestMatch(sc);
+	if (!tempdecl || global.errors)
+	{   inst = this;
+	    //printf("error return %p, %d\n", tempdecl, global.errors);
+	    return;		// error recovery
+	}
+    }
+
+    isNested(tiargs);
+
+    /* See if there is an existing TemplateInstantiation that already
+     * implements the typeargs. If so, just refer to that one instead.
+     */
+
+    for (size_t i = 0; i < tempdecl->instances.dim; i++)
+    {
+	TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i];
+#if LOG
+	printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars());
+#endif
+	assert(tdtypes.dim == ti->tdtypes.dim);
+
+	// Nesting must match
+	if (isnested != ti->isnested)
+	    continue;
+#if 0
+	if (isnested && sc->parent != ti->parent)
+	    continue;
+#endif
+	for (size_t j = 0; j < tdtypes.dim; j++)
+	{   Object *o1 = (Object *)tdtypes.data[j];
+	    Object *o2 = (Object *)ti->tdtypes.data[j];
+	    if (!match(o1, o2, tempdecl, sc))
+		goto L1;
+	}
+
+	// It's a match
+	inst = ti;
+	parent = ti->parent;
+#if LOG
+	printf("\tit's a match with instance %p\n", inst);
+#endif
+	return;
+
+     L1:
+	;
+    }
+
+    /* So, we need to implement 'this' instance.
+     */
+#if LOG
+    printf("\timplement template instance '%s'\n", toChars());
+#endif
+    unsigned errorsave = global.errors;
+    inst = this;
+    int tempdecl_instance_idx = tempdecl->instances.dim;
+    tempdecl->instances.push(this);
+    parent = tempdecl->parent;
+    //printf("parent = '%s'\n", parent->kind());
+
+    ident = genIdent();		// need an identifier for name mangling purposes.
+
+#if 1
+    if (isnested)
+	parent = isnested;
+#endif
+    //printf("parent = '%s'\n", parent->kind());
+
+    // Add 'this' to the enclosing scope's members[] so the semantic routines
+    // will get called on the instance members
+#if 1
+    int dosemantic3 = 0;
+    {	Array *a;
+
+	Scope *scx = sc;
+#if 0
+	for (scx = sc; scx; scx = scx->enclosing)
+	    if (scx->scopesym)
+		break;
+#endif
+
+	//if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
+	if (scx && scx->scopesym && scx->scopesym->members && !scx->scopesym->isTemplateMixin())
+	{
+	    //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
+	    a = scx->scopesym->members;
+	}
+	else
+	{   Module *m = sc->module->importedFrom;
+	    //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars());
+	    a = m->members;
+	    if (m->semanticdone >= 3)
+		dosemantic3 = 1;
+	}
+	for (int i = 0; 1; i++)
+	{
+	    if (i == a->dim)
+	    {
+		a->push(this);
+		break;
+	    }
+	    if (this == (Dsymbol *)a->data[i])	// if already in Array
+		break;
+	}
+    }
+#endif
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+    // Create our own scope for the template parameters
+    Scope *scope = tempdecl->scope;
+    if (!scope)
+    {
+	error("forward reference to template declaration %s\n", tempdecl->toChars());
+	return;
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    argsym = new ScopeDsymbol();
+    argsym->parent = scope->parent;
+    scope = scope->push(argsym);
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members of template instance to template instance symbol table
+//    parent = scope->scopesym;
+    symtab = new DsymbolTable();
+    int memnum = 0;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum);
+#endif
+	memnum |= s->addMember(scope, this, memnum);
+    }
+#if LOG
+    printf("adding members done\n");
+#endif
+
+    /* See if there is only one member of template instance, and that
+     * member has the same name as the template instance.
+     * If so, this template instance becomes an alias for that member.
+     */
+    //printf("members->dim = %d\n", members->dim);
+    if (members->dim)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s) && s)
+	{
+	    //printf("s->kind = '%s'\n", s->kind());
+	    //s->print();
+	    //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars());
+	    if (s->ident && s->ident->equals(tempdecl->ident))
+	    {
+		//printf("setting aliasdecl\n");
+		aliasdecl = new AliasDeclaration(loc, s->ident, s);
+	    }
+	}
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars());
+    sc2->parent = /*isnested ? sc->parent :*/ this;
+    sc2->tinst = this;
+
+#if !IN_LLVM    
+#if _WIN32
+  __try
+  {
+#endif
+#endif
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+	//printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars());
+//	if (isnested)
+//	    s->parent = sc->parent;
+	//printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	s->semantic(sc2);
+	//printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	sc2->module->runDeferredSemantic();
+    }
+#if !IN_LLVM    
+#if _WIN32
+  }
+  __except (__ehfilter(GetExceptionInformation()))
+  {
+    global.gag = 0;			// ensure error message gets printed
+    error("recursive expansion");
+    fatal();
+  }
+#endif
+#endif
+
+    /* If any of the instantiation members didn't get semantic() run
+     * on them due to forward references, we cannot run semantic2()
+     * or semantic3() yet.
+     */
+    for (size_t i = 0; i < Module::deferred.dim; i++)
+    {	Dsymbol *sd = (Dsymbol *)Module::deferred.data[i];
+
+	if (sd->parent == this)
+	    goto Laftersemantic;
+    }
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	/* BUG 782: this has problems if the classes this depends on
+	 * are forward referenced. Find a way to defer semantic()
+	 * on this template.
+	 */
+	semantic2(sc2);
+
+    if (sc->func || dosemantic3)
+    {
+	semantic3(sc2);
+    }
+
+  Laftersemantic:
+    sc2->pop();
+
+    scope->pop();
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+	if(tinst)
+	    tinst->printInstantiationTrace();
+	errors = 1;
+	if (global.gag)
+	    tempdecl->instances.remove(tempdecl_instance_idx);
+    }
+
+#if LOG
+    printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+
+void TemplateInstance::semanticTiargs(Scope *sc)
+{
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    if (semantictiargsdone)
+	return;
+    semantictiargsdone = 1;
+    semanticTiargs(loc, sc, tiargs, 0);
+}
+
+/**********************************
+ * Input:
+ *	flags	1: replace const variables with their initializers
+ */
+
+void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags)
+{
+    // Run semantic on each argument, place results in tiargs[]
+    //printf("+TemplateInstance::semanticTiargs()\n");
+    if (!tiargs)
+	return;
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+
+	//printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
+	if (ta)
+	{
+	    //printf("type %s\n", ta->toChars());
+	    // It might really be an Expression or an Alias
+	    ta->resolve(loc, sc, &ea, &ta, &sa);
+	    if (ea)
+	    {
+		ea = ea->semantic(sc);
+		/* This test is to skip substituting a const var with
+		 * its initializer. The problem is the initializer won't
+		 * match with an 'alias' parameter. Instead, do the
+		 * const substitution in TemplateValueParameter::matchArg().
+		 */
+		if (ea->op != TOKvar || flags & 1)
+		    ea = ea->optimize(WANTvalue | WANTinterpret);
+		tiargs->data[j] = ea;
+	    }
+	    else if (sa)
+	    {	tiargs->data[j] = sa;
+		TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
+		if (d)
+		{
+		    size_t dim = d->objects->dim;
+		    tiargs->remove(j);
+		    tiargs->insert(j, d->objects);
+		    j--;
+		}
+	    }
+	    else if (ta)
+	    {
+		if (ta->ty == Ttuple)
+		{   // Expand tuple
+		    TypeTuple *tt = (TypeTuple *)ta;
+		    size_t dim = tt->arguments->dim;
+		    tiargs->remove(j);
+		    if (dim)
+		    {	tiargs->reserve(dim);
+			for (size_t i = 0; i < dim; i++)
+			{   Argument *arg = (Argument *)tt->arguments->data[i];
+			    tiargs->insert(j + i, arg->type);
+			}
+		    }
+		    j--;
+		}
+		else
+		    tiargs->data[j] = ta;
+	    }
+	    else
+	    {
+		assert(global.errors);
+		tiargs->data[j] = Type::terror;
+	    }
+	}
+	else if (ea)
+	{
+	    if (!ea)
+	    {	assert(global.errors);
+		ea = new IntegerExp(0);
+	    }
+	    assert(ea);
+	    ea = ea->semantic(sc);
+	    if (ea->op != TOKvar || flags & 1)
+		ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[j] = ea;
+	    if (ea->op == TOKtype)
+		tiargs->data[j] = ea->type;
+	}
+	else if (sa)
+	{
+	}
+	else
+	{
+	    assert(0);
+	}
+	//printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]);
+    }
+#if 0
+    printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this);
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+
+	printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+    }
+#endif
+}
+
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ */
+
+TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc)
+{
+    //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars());
+    if (!tempdecl)
+    {
+	/* Given:
+	 *    foo!( ... )
+	 * figure out which TemplateDeclaration foo refers to.
+	 */
+	Dsymbol *s;
+	Dsymbol *scopesym;
+	Identifier *id;
+	int i;
+
+	id = name;
+	s = sc->search(loc, id, &scopesym);
+	if (!s)
+	{   error("identifier '%s' is not defined", id->toChars());
+	    return NULL;
+	}
+#if LOG
+	printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind());
+	if (s->parent)
+	    printf("s->parent = '%s'\n", s->parent->toChars());
+#endif
+	withsym = scopesym->isWithScopeSymbol();
+
+	/* We might have found an alias within a template when
+	 * we really want the template.
+	 */
+	TemplateInstance *ti;
+	if (s->parent &&
+	    (ti = s->parent->isTemplateInstance()) != NULL)
+	{
+	    if (
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+		s = tempdecl;
+	    }
+	}
+
+	s = s->toAlias();
+
+	/* It should be a TemplateDeclaration, not some other symbol
+	 */
+	tempdecl = s->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    if (!s->parent && global.errors)
+		return NULL;
+	    if (!s->parent && s->getType())
+	    {	Dsymbol *s2 = s->getType()->toDsymbol(sc);
+		if (!s2)
+		{
+		    error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		    return NULL;
+		}
+		s = s2;
+	    }
+#ifdef DEBUG
+	    //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars());
+#endif
+	    //assert(s->parent);
+	    TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
+	    if (ti &&
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+	    }
+	    else
+	    {
+		error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		return NULL;
+	    }
+	}
+    }
+    else
+	assert(tempdecl->isTemplateDeclaration());
+    return tempdecl;
+}
+
+TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc)
+{
+    /* Since there can be multiple TemplateDeclaration's with the same
+     * name, look for the best match.
+     */
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    MATCH m_best = MATCHnomatch;
+    Objects dedtypes;
+
+#if LOG
+    printf("TemplateInstance::findBestMatch()\n");
+#endif
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	MATCH m;
+
+//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]);
+
+	// If more arguments than parameters,
+	// then this is no match.
+	if (td->parameters->dim < tiargs->dim)
+	{
+	    if (!td->isVariadic())
+		continue;
+	}
+
+	dedtypes.setDim(td->parameters->dim);
+	dedtypes.zero();
+	if (!td->scope)
+	{
+	    error("forward reference to template declaration %s", td->toChars());
+	    return NULL;
+	}
+	m = td->matchWithInstance(this, &dedtypes, 0);
+	//printf("matchWithInstance = %d\n", m);
+	if (!m)			// no match at all
+	    continue;
+
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	MATCH c1 = td->leastAsSpecialized(td_best);
+	MATCH c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 > c2)
+	    goto Ltd;
+	else if (c1 < c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	td_best = td;
+	m_best = m;
+	tdtypes.setDim(dedtypes.dim);
+	memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *));
+	continue;
+    }
+
+    if (!td_best)
+    {
+	if (tempdecl && !tempdecl->overnext)
+	    // Only one template, so we can give better error message
+	    error("%s does not match template declaration %s", toChars(), tempdecl->toChars());
+	else
+	    error("%s does not match any template declaration", toChars());
+	return NULL;
+    }
+    if (td_ambig)
+    {
+	error("%s matches more than one template declaration, %s and %s",
+		toChars(), td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best
+     */
+    tempdecl = td_best;
+
+#if 0
+    /* Cast any value arguments to be same type as value parameter
+     */
+    for (size_t i = 0; i < tiargs->dim; i++)
+    {	Object *o = (Object *)tiargs->data[i];
+	Expression *ea = isExpression(o);	// value argument
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	assert(tp);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	if (tvp)
+	{
+	    assert(ea);
+	    ea = ea->castTo(tvp->valType);
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[i] = (Object *)ea;
+	}
+    }
+#endif
+
+#if LOG
+    printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars());
+#endif
+    return tempdecl;
+}
+
+
+/*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ */
+
+int TemplateInstance::isNested(Objects *args)
+{   int nested = 0;
+    //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars());
+
+    /* A nested instance happens when an argument references a local
+     * symbol that is on the stack.
+     */
+    for (size_t i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	if (ea)
+	{
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		goto Lsa;
+	    }
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->isDataseg() &&
+#if DMDV2
+		!(d->storage_class & STCmanifest) &&
+#endif
+		(!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
+		!isTemplateMixin())
+	    {
+		// if module level template
+		if (tempdecl->toParent()->isModule())
+		{   Dsymbol *dparent = d->toParent();
+		    if (!isnested)
+			isnested = dparent;
+		    else if (isnested != dparent)
+		    {
+			/* Select the more deeply nested of the two.
+			 * Error if one is not nested inside the other.
+			 */
+			for (Dsymbol *p = isnested; p; p = p->parent)
+			{
+			    if (p == dparent)
+				goto L1;	// isnested is most nested
+			}
+			for (Dsymbol *p = dparent; 1; p = p->parent)
+			{
+			    if (p == isnested)
+			    {	isnested = dparent;
+				goto L1;	// dparent is most nested
+			    }
+			}
+			error("is nested in both %s and %s", isnested->toChars(), dparent->toChars());
+		    }
+		  L1:
+		    //printf("\tnested inside %s\n", isnested->toChars());
+		    nested |= 1;
+		}
+		else
+		    error("cannot use local '%s' as parameter to non-global template %s", d->toChars(), tempdecl->toChars());
+	    }
+	}
+	else if (va)
+	{
+	    nested |= isNested(&va->objects);
+	}
+    }
+    return nested;
+}
+
+/****************************************
+ * This instance needs an identifier for name mangling purposes.
+ * Create one by taking the template declaration name and adding
+ * the type signature for it.
+ */
+
+Identifier *TemplateInstance::genIdent()
+{   OutBuffer buf;
+    char *id;
+    Objects *args;
+
+    //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+    id = tempdecl->ident->toChars();
+    buf.printf("__T%"PRIuSIZE"%s", strlen(id), id);
+    args = tiargs;
+    for (int i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	//printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va);
+	if (ta)
+	{
+	    buf.writeByte('T');
+	    if (ta->deco)
+		buf.writestring(ta->deco);
+	    else
+	    {
+#ifdef DEBUG
+		printf("ta = %d, %s\n", ta->ty, ta->toChars());
+#endif
+		assert(global.errors);
+	    }
+	}
+	else if (ea)
+	{
+	  Lea:
+	    sinteger_t v;
+	    real_t r;
+
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    buf.writeByte('V');
+	    if (ea->op == TOKtuple)
+	    {	ea->error("tuple is not a valid template value argument");
+		continue;
+	    }
+#if 1
+	    /* Use deco that matches what it would be for a function parameter
+	     */
+	    //buf.writestring(ea->type->toHeadMutable()->deco);
+	    buf.writestring(ea->type->deco);
+#else
+	    // Use type of parameter, not type of argument
+	    TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	    assert(tp);
+	    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	    assert(tvp);
+	    buf.writestring(tvp->valType->deco);
+#endif
+	    ea->toMangleBuffer(&buf);
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    buf.writeByte('S');
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->type->deco)
+	    {	error("forward reference of %s", d->toChars());
+		continue;
+	    }
+#if 0
+	    VarDeclaration *v = sa->isVarDeclaration();
+	    if (v && v->storage_class & STCmanifest)
+	    {	ExpInitializer *ei = v->init->isExpInitializer();
+		if (ei)
+		{
+		    ea = ei->exp;
+		    goto Lea;
+		}
+	    }
+#endif
+	    const char *p = sa->mangle();
+	    buf.printf("%zu%s", strlen(p), p);
+	}
+	else if (va)
+	{
+	    assert(i + 1 == args->dim);		// must be last one
+	    args = &va->objects;
+	    i = -1;
+	}
+	else
+	    assert(0);
+    }
+    buf.writeByte('Z');
+    id = buf.toChars();
+    buf.data = NULL;
+    //printf("\tgenIdent = %s\n", id);
+    return new Identifier(id, TOKidentifier);
+}
+
+
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+
+void TemplateInstance::declareParameters(Scope *scope)
+{
+    //printf("TemplateInstance::declareParameters()\n");
+    for (int i = 0; i < tdtypes.dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	//Object *o = (Object *)tiargs->data[i];
+	Object *o = (Object *)tdtypes.data[i];		// initializer for tp
+
+	//printf("\ttdtypes[%d] = %p\n", i, o);
+	tempdecl->declareParameter(scope, tp, o);
+    }
+}
+
+
+void TemplateInstance::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	sc->tinst = this;
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateInstance::semantic3(Scope *sc)
+{
+#if LOG
+    printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone);
+#endif
+//if (toChars()[0] == 'D') *(char*)0=0;
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	sc->tinst = this;
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateInstance::toObjFile(int multiobj)
+{
+#if LOG
+    printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this);
+#endif
+    if (!errors && members)
+    {
+	if (multiobj)
+	    // Append to list of object files to be written later
+	    //obj_append(this);
+        assert(0 && "multiobj");
+	else
+	{
+	    for (int i = 0; i < members->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)members->data[i];
+		s->toObjFile(multiobj);
+	    }
+	}
+    }
+}
+
+void TemplateInstance::inlineScan()
+{
+#if LOG
+    printf("TemplateInstance::inlineScan('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->inlineScan();
+	}
+    }
+}
+
+void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    int i;
+
+    Identifier *id = name;
+    buf->writestring(id->toChars());
+    buf->writestring("!(");
+    if (nest)
+	buf->writestring("...");
+    else
+    {
+	nest++;
+	Objects *args = tiargs;
+	for (i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *oarg = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, oarg);
+	}
+	nest--;
+    }
+    buf->writeByte(')');
+}
+
+
+Dsymbol *TemplateInstance::toAlias()
+{
+#if LOG
+    printf("TemplateInstance::toAlias()\n");
+#endif
+    if (!inst)
+    {	error("cannot resolve forward reference");
+	return this;
+    }
+
+    if (inst != this)
+	return inst->toAlias();
+
+    if (aliasdecl)
+	return aliasdecl->toAlias();
+
+    return inst;
+}
+
+AliasDeclaration *TemplateInstance::isAliasDeclaration()
+{
+    return aliasdecl;
+}
+
+const char *TemplateInstance::kind()
+{
+    return "template instance";
+}
+
+int TemplateInstance::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+char *TemplateInstance::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+void TemplateInstance::printInstantiationTrace()
+{
+    if(global.gag)
+	return;
+
+    const int max_shown = 6;
+
+    // determine instantiation depth
+    int n_instantiations = 1;
+    TemplateInstance* cur = this;
+    while(cur = cur->tinst)
+	++n_instantiations;
+
+    // show full trace only if it's short or verbose is on
+    if(n_instantiations <= max_shown || global.params.verbose)
+    {
+	cur = this;
+	while(cur)
+	{
+	    fprintf(stdmsg,"    instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars());
+	    cur = cur->tinst;
+	}
+    }
+    else
+    {
+	cur = this;
+	size_t i = 0;
+	for(; i < max_shown/2; ++i, cur = cur->tinst)
+	    fprintf(stdmsg,"    instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars());
+	fprintf(stdmsg,"    ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown);
+	for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) 
+	{}
+	for(; i < n_instantiations; ++i, cur = cur->tinst) 
+	    fprintf(stdmsg,"    instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars());
+    }
+}
+
+/* ======================== TemplateMixin ================================ */
+
+TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual,
+	Array *idents, Objects *tiargs)
+	: TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1])
+{
+    //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
+    this->ident = ident;
+    this->tqual = tqual;
+    this->idents = idents;
+    this->tiargs = tiargs ? tiargs : new Objects();
+    this->scope = NULL;
+}
+
+Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s)
+{   TemplateMixin *tm;
+
+    Array *ids = new Array();
+    ids->setDim(idents->dim);
+    for (int i = 0; i < idents->dim; i++)
+    {	// Matches TypeQualified::syntaxCopyHelper()
+        Identifier *id = (Identifier *)idents->data[i];
+        if (id->dyncast() == DYNCAST_DSYMBOL)
+        {
+            TemplateInstance *ti = (TemplateInstance *)id;
+
+            ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+            id = (Identifier *)ti;
+        }
+        ids->data[i] = id;
+    }
+
+    tm = new TemplateMixin(loc, ident,
+		(Type *)(tqual ? tqual->syntaxCopy() : NULL),
+		ids, tiargs);
+    TemplateInstance::syntaxCopy(tm);
+    return tm;
+}
+
+void TemplateMixin::semantic(Scope *sc)
+{
+#if LOG
+    printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+    fflush(stdout);
+#endif
+    if (semanticdone &&
+	// This for when a class/struct contains mixin members, and
+	// is done over because of forward references
+	(!parent || !toParent()->isAggregateDeclaration()))
+    {
+#if LOG
+	printf("\tsemantic done\n");
+#endif
+	return;
+    }
+    if (!semanticdone)
+	semanticdone = 1;
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+
+#if !IN_LLVM
+    // dont know what this is
+    util_progress();
+#endif
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    // Follow qualifications to find the TemplateDeclaration
+    if (!tempdecl)
+    {	Dsymbol *s;
+	int i;
+	Identifier *id;
+
+	if (tqual)
+	{   s = tqual->toDsymbol(sc);
+	    i = 0;
+	}
+	else
+	{
+	    i = 1;
+	    id = (Identifier *)idents->data[0];
+	    switch (id->dyncast())
+	    {
+		case DYNCAST_IDENTIFIER:
+		    s = sc->search(loc, id, NULL);
+		    break;
+
+		case DYNCAST_DSYMBOL:
+		{
+		    TemplateInstance *ti = (TemplateInstance *)id;
+		    ti->semantic(sc);
+		    s = ti;
+		    break;
+		}
+		default:
+		    assert(0);
+	    }
+	}
+
+	for (; i < idents->dim; i++)
+	{
+	    if (!s)
+		break;
+	    id = (Identifier *)idents->data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (!s)
+	{
+	    error("is not defined");
+	    inst = this;
+	    return;
+	}
+	tempdecl = s->toAlias()->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    error("%s isn't a template", s->toChars());
+	    inst = this;
+	    return;
+	}
+    }
+
+    // Look for forward reference
+    assert(tempdecl);
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    /* Cannot handle forward references if mixin is a struct member,
+	     * because addField must happen during struct's semantic, not
+	     * during the mixin semantic.
+	     * runDeferred will re-run mixin's semantic outside of the struct's
+	     * semantic.
+	     */
+	    semanticdone = 0;
+	    AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
+	    if (ad)
+		ad->sizeok = 2;
+	    else
+	    {
+		// Forward reference
+		//printf("forward reference - deferring\n");
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    return;
+	}
+    }
+
+    // Run semantic on each argument, place results in tiargs[]
+    semanticTiargs(sc);
+
+    tempdecl = findBestMatch(sc);
+    if (!tempdecl)
+    {	inst = this;
+	return;		// error recovery
+    }
+
+    if (!ident)
+	ident = genIdent();
+
+    inst = this;
+    parent = sc->parent;
+
+    /* Detect recursive mixin instantiations.
+     */
+    for (Dsymbol *s = parent; s; s = s->parent)
+    {
+	//printf("\ts = '%s'\n", s->toChars());
+	TemplateMixin *tm = s->isTemplateMixin();
+	if (!tm || tempdecl != tm->tempdecl)
+	    continue;
+
+	/* Different argument list lengths happen with variadic args
+	 */
+	if (tiargs->dim != tm->tiargs->dim)
+	    continue;
+
+	for (int i = 0; i < tiargs->dim; i++)
+	{   Object *o = (Object *)tiargs->data[i];
+	    Type *ta = isType(o);
+	    Expression *ea = isExpression(o);
+	    Dsymbol *sa = isDsymbol(o);
+	    Object *tmo = (Object *)tm->tiargs->data[i];
+	    if (ta)
+	    {
+		Type *tmta = isType(tmo);
+		if (!tmta)
+		    goto Lcontinue;
+		if (!ta->equals(tmta))
+		    goto Lcontinue;
+	    }
+	    else if (ea)
+	    {	Expression *tme = isExpression(tmo);
+		if (!tme || !ea->equals(tme))
+		    goto Lcontinue;
+	    }
+	    else if (sa)
+	    {
+		Dsymbol *tmsa = isDsymbol(tmo);
+		if (sa != tmsa)
+		    goto Lcontinue;
+	    }
+	    else
+		assert(0);
+	}
+	error("recursive mixin instantiation");
+	return;
+
+    Lcontinue:
+	continue;
+    }
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+    if (!members)
+	return;
+
+    symtab = new DsymbolTable();
+
+    for (Scope *sce = sc; 1; sce = sce->enclosing)
+    {
+	ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
+	if (sds)
+	{
+	    sds->importScope(this, PROTpublic);
+	    break;
+	}
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    Scope *scy = sc;
+    scy = sc->push(this);
+    scy->parent = this;
+
+    argsym = new ScopeDsymbol();
+    argsym->parent = scy->parent;
+    Scope *scope = scy->push(argsym);
+
+    unsigned errorsave = global.errors;
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members to enclosing scope, as well as this scope
+    for (unsigned i = 0; i < members->dim; i++)
+    {   Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->addMember(scope, this, i);
+	//sc->insert(s);
+	//printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
+	//printf("s->parent = %s\n", s->parent->toChars());
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    sc2->offset = sc->offset;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc2);
+    }
+    sc->offset = sc2->offset;
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	semantic2(sc2);
+
+    if (sc->func)
+    {
+	semantic3(sc2);
+    }
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+    }
+
+    sc2->pop();
+
+    scope->pop();
+
+//    if (!isAnonymous())
+    {
+	scy->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+void TemplateMixin::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	    printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateMixin::semantic3(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+#if LOG
+    printf("TemplateMixin::semantic3('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateMixin::inlineScan()
+{
+    TemplateInstance::inlineScan();
+}
+
+const char *TemplateMixin::kind()
+{
+    return "mixin";
+}
+
+int TemplateMixin::oneMember(Dsymbol **ps)
+{
+    return Dsymbol::oneMember(ps);
+}
+
+int TemplateMixin::hasPointers()
+{
+    //printf("TemplateMixin::hasPointers() %s\n", toChars());
+    for (size_t i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf(" s = %s %s\n", s->kind(), s->toChars());
+	if (s->hasPointers())
+	{
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+char *TemplateMixin::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    TemplateInstance::toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin ");
+
+    for (int i = 0; i < idents->dim; i++)
+    {   Identifier *id = (Identifier *)idents->data[i];
+
+    	if (i)
+	    buf->writeByte('.');
+	buf->writestring(id->toChars());
+    }
+    buf->writestring("!(");
+    if (tiargs)
+    {
+        for (int i = 0; i < tiargs->dim; i++)
+        {   if (i)
+                buf->writebyte(',');
+	    Object *oarg = (Object *)tiargs->data[i];
+	    Type *t = isType(oarg);
+	    Expression *e = isExpression(oarg);
+	    Dsymbol *s = isDsymbol(oarg);
+	    if (t)
+		t->toCBuffer(buf, NULL, hgs);
+	    else if (e)
+		e->toCBuffer(buf, hgs);
+	    else if (s)
+	    {
+		char *p = s->ident ? s->ident->toChars() : s->toChars();
+		buf->writestring(p);
+	    }
+	    else if (!oarg)
+	    {
+		buf->writestring("NULL");
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+        }
+    }
+    buf->writebyte(')');
+    if (ident)
+    {
+	buf->writebyte(' ');
+	buf->writestring(ident->toChars());
+    }
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+
+void TemplateMixin::toObjFile(int multiobj)
+{
+    //printf("TemplateMixin::toObjFile('%s')\n", toChars());
+    TemplateInstance::toObjFile(multiobj);
+}
+